Skip to content

Commit 77eb320

Browse files
Add unit tests for DataverseClient (#71)
* test: add unit tests for DataverseClient Added comprehensive unit tests for the DataverseClient class in tests/unit/test_client.py. These tests mock the internal _ODataClient to verify that the public API methods (create, get, update, delete) correctly delegate to the underlying OData implementation. * Format test_client.py to pass style checks
1 parent 8aa9945 commit 77eb320

1 file changed

Lines changed: 129 additions & 0 deletions

File tree

tests/unit/test_client.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT license.
3+
4+
import unittest
5+
from unittest.mock import MagicMock
6+
7+
from azure.core.credentials import TokenCredential
8+
9+
from PowerPlatform.Dataverse.client import DataverseClient
10+
11+
12+
class TestDataverseClient(unittest.TestCase):
13+
def setUp(self):
14+
"""Set up test fixtures before each test method."""
15+
# Create mock credential
16+
self.mock_credential = MagicMock(spec=TokenCredential)
17+
self.base_url = "https://example.crm.dynamics.com"
18+
19+
# Initialize the client under test
20+
self.client = DataverseClient(self.base_url, self.mock_credential)
21+
22+
# Mock the internal _odata client
23+
# This ensures we verify logic without making actual HTTP calls
24+
self.client._odata = MagicMock()
25+
26+
def test_create_single(self):
27+
"""Test create method with a single record."""
28+
# Setup mock return values
29+
# _create must return a GUID string
30+
self.client._odata._create.return_value = "00000000-0000-0000-0000-000000000000"
31+
# _entity_set_from_schema_name should return the plural entity set name
32+
self.client._odata._entity_set_from_schema_name.return_value = "accounts"
33+
34+
# Execute test
35+
self.client.create("account", {"name": "Contoso Ltd"})
36+
37+
# Verify
38+
# Ensure _entity_set_from_schema_name was called and its result ("accounts") was passed to _create
39+
self.client._odata._create.assert_called_once_with("accounts", "account", {"name": "Contoso Ltd"})
40+
41+
def test_create_multiple(self):
42+
"""Test create method with multiple records."""
43+
payloads = [{"name": "Company A"}, {"name": "Company B"}, {"name": "Company C"}]
44+
45+
# Setup mock return values
46+
# _create_multiple must return a list of GUID strings
47+
self.client._odata._create_multiple.return_value = [
48+
"00000000-0000-0000-0000-000000000001",
49+
"00000000-0000-0000-0000-000000000002",
50+
"00000000-0000-0000-0000-000000000003",
51+
]
52+
self.client._odata._entity_set_from_schema_name.return_value = "accounts"
53+
54+
# Execute test
55+
self.client.create("account", payloads)
56+
57+
# Verify
58+
self.client._odata._create_multiple.assert_called_once_with("accounts", "account", payloads)
59+
60+
def test_update_single(self):
61+
"""Test update method with a single record."""
62+
self.client.update("account", "00000000-0000-0000-0000-000000000000", {"telephone1": "555-0199"})
63+
self.client._odata._update.assert_called_once_with(
64+
"account", "00000000-0000-0000-0000-000000000000", {"telephone1": "555-0199"}
65+
)
66+
67+
def test_update_multiple(self):
68+
"""Test update method with multiple records (broadcast)."""
69+
ids = [
70+
"00000000-0000-0000-0000-000000000001",
71+
"00000000-0000-0000-0000-000000000002",
72+
]
73+
changes = {"statecode": 1}
74+
75+
self.client.update("account", ids, changes)
76+
self.client._odata._update_by_ids.assert_called_once_with("account", ids, changes)
77+
78+
def test_delete_single(self):
79+
"""Test delete method with a single record."""
80+
self.client.delete("account", "00000000-0000-0000-0000-000000000000")
81+
self.client._odata._delete.assert_called_once_with("account", "00000000-0000-0000-0000-000000000000")
82+
83+
def test_delete_multiple(self):
84+
"""Test delete method with multiple records."""
85+
ids = [
86+
"00000000-0000-0000-0000-000000000001",
87+
"00000000-0000-0000-0000-000000000002",
88+
]
89+
# Mock return value for bulk delete job ID
90+
self.client._odata._delete_multiple.return_value = "job-guid-123"
91+
92+
job_id = self.client.delete("account", ids)
93+
94+
self.client._odata._delete_multiple.assert_called_once_with("account", ids)
95+
self.assertEqual(job_id, "job-guid-123")
96+
97+
def test_get_single(self):
98+
"""Test get method with a single record ID."""
99+
# Setup mock return value
100+
expected_record = {"accountid": "00000000-0000-0000-0000-000000000000", "name": "Contoso"}
101+
self.client._odata._get.return_value = expected_record
102+
103+
result = self.client.get("account", "00000000-0000-0000-0000-000000000000")
104+
105+
self.client._odata._get.assert_called_once_with("account", "00000000-0000-0000-0000-000000000000", select=None)
106+
self.assertEqual(result, expected_record)
107+
108+
def test_get_multiple(self):
109+
"""Test get method for querying multiple records."""
110+
# Setup mock return value (iterator)
111+
expected_batch = [{"accountid": "1", "name": "A"}, {"accountid": "2", "name": "B"}]
112+
self.client._odata._get_multiple.return_value = iter([expected_batch])
113+
114+
# Execute query
115+
result_iterator = self.client.get("account", filter="statecode eq 0", top=10)
116+
117+
# Consume iterator to verify content
118+
results = list(result_iterator)
119+
120+
self.client._odata._get_multiple.assert_called_once_with(
121+
"account",
122+
select=None,
123+
filter="statecode eq 0",
124+
orderby=None,
125+
top=10,
126+
expand=None,
127+
page_size=None,
128+
)
129+
self.assertEqual(results, [expected_batch])

0 commit comments

Comments
 (0)