Search code examples
pythonunit-testingmockingazure-service-principal

Using real data when mocking objects in unit test


I am mocking in some unit tests, and I am wondering whether is fine or recommended to use real data (I am dealing with non-sensitive data) when mocking.

For instance, I am testing the user's members which are allowed to authenticate in an application by using an azure service principal here:

def create_mock(status_code, data):
    def mocked_requests(*args, **kwargs):
        class MockResponse:
            def __init__(self, status_code, json_data):
                self.json_data = json_data
                self.status_code = status_code

            def json(self):
                return self.json_data

        return MockResponse(status_code, data)

    return mocked_requests

class RolesTestCase(unittest.TestCase):
    @mock.patch('requests.get',
                side_effect=create_mock(
                    200,
                    # HERE MY OBJECT OR DATA MOCKED.
                    {
                        "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#servicePrincipals('99999')/appRoleAssignedTo",
                        "value": [{
                            "id": "99999",
                            "deletedDateTime": "null",
                            "appRoleId": "00000000-0000-0000-0000-000000000000",
                            "createdDateTime": "2021-03-21T17:15:40.516616Z",
                            "principalDisplayName": "Bernardo Garcia Loaiza",
                            "principalId": "99999",
                            "principalType": "User",
                            "resourceDisplayName": "my-service-principal-name",
                            "resourceId": "99999"
                        }]
                    }
                 )
                )
    @mock.patch('roles.get_sp_object_id')
    def test_get_user_role_assignments(self, get_sp_object_id, mock):
        token = "FOOBAR"
        get_user_role_assignments(token, {"id": "123", "name": "group_name"})
        get_sp_object_id.assert_called_with(token, {"id": "123", "name": "group_name"})

At the @mock.patch('requests.get, ...' code section above, is ok if instead of 99999 values on the JSON doc, I put the real values?


Solution

  • The question's probably a bit broad. But in general you want to go for something like this:

    In unit tests, try determine all classes of inputs that may result in different behaviour, and test with an example from each. For example, a function involving a square root should be tested with a positive number, 0, and a negative number, to see that it behaves correctly in each case. If you only use the data you're currently interested in, you will have a brittle system. If either (a) the data your software processes changes or (b) your function is called by another developer in another context, then you could end up with a function that passed the tests but breaks in production. If you want to include one example of real data as a sanity check then why not.

    In end-to-end tests and integration tests you'll usually want to use real records.

    But really it depends on so many things: Are you using test-driven development? Are you using CI/CD? what is your test coverage? what is your budget? what is the cost of failure in production? How confident are you that you know what type of data to expect? How likely is it that project scope will expand or change? Do tests even make sense for the functionality? etc