I have a python function that creates a Client object from the aiosnow module, which is an API wrapper for ServiceNow like this:
from aiosnow import Client def create_snow_client(url: str, user_name: str, pwd: str) -> Client: """Creates ServiceNow client object for interacting with the API.""" client = Client( url, basic_auth=(user_name, pwd), ) return client
Assuming I will not have internet connection during unit testing, how or what part am I supposed to make the unit test for, which part am I supposed to mock?
Advertisement
Answer
One approach is just to guarantee that the Client
constructor has been called. You can accomplish this with unittest.mock.Mock().assert_called
(or some variant of it, like assert_called_with
). This will entail mocking the Client
class, so that when the test runs and you call the Client
constructor, no code from Client
actually runs. The mock gets called and then you can make assertions based on what you expected to happen.
This is a correct approach because you and your test don’t care about the inner workings of the Client
class. You’re testing your function which is supposed to create a client, not that Client
works correctly. By mocking out the Client
class, your test simply guarantees that your code instantiated a Client
, but doesn’t run any Client
code.
Here’s an example:
from unittest.mock import patch class Foo(): def __init__(self): print("New Foo!") def use_foo(): print(f"foo: {Foo()}") @patch("__main__.Foo") def test_foo(mocked_foo): use_foo() print(f"Mocked Foo called? {mocked_foo.called}") def main(): print("Using foon") use_foo() print("nTesting foon") test_foo() if __name__ == "__main__": main()
and here’s the corresponding output:
Using foo New Foo! foo: <__main__.Foo object at 0x7fdfcaba2ac0> Testing foo foo: <MagicMock name='Foo()' id='140599155357056'> Mocked Foo called? True
You can see that "New Foo"
did not appear in the output of the test, because the class has been mocked.
You can read more about mocking in the Python docs.