Mock & Unit Tests in Python: Examples

After the introduction of this python library, I will deep into its most useful mock properties using some enjoyable unit tests using Mock in Python.

MOCK WHAT A METHOD RETURNS

Sometimes, you need that a method always returns some data for a test avoiding some issues or different results running the same test.

In this case, it is better to use some mocked values as return of a method.

To use this functionality, we need to assign to return_value property the values you wish to use in test.

A real example of this test could be when we need to get a list of devices in order to do some operation with them.

@patch(“device_services.get_android_devices”)
def some_operation_with_devices_test(mock_android_devices):
    mock_android_devices.return_value = get_sample_android_devices()
    device_list = device_services.get_android_devices()
    …
...

def get_sample_android_devices():
     return [DeviceObject(1), DeviceObject(2)]

In this case, all code existing in get_android_devices will be replaced by the code existing in get_sample_android_devices method. So, instead of accessing to database to get all android devices existing, device_list will contain a custom list of device objects.

MOCK THAT A METHOD HAS BEEN CALLED

It is possible you need to create a test in which you just assert that the mock object has been called.

When would you really want it? For example, when we need to push notification to devices.

We know that the method to send notifications to devices is working flawlessly (because it is just a Web Service call), but we don’t want to receive notifications each time unit tests are run on those devices we have for testing.

To test this, we would assert the called property is a boolean set to true.

Getting back the situation explained above, the following block of code would test push notifications to Android devices.

@patch(“notification_service.send_android_notifications”)
def test_send_android_notification(mock_android_notif):
    devices = device_service.get_list_of_android_devices()
    message = u“I am testing notifications”

    notification_service.send_notification(devices, message)

    assertTrue(mock_android_notif.called)

In this test, send_android_notifications from notifications_service has been reached and called.

MOCK SIDE EFFECTS

Mock objects allows you to perform side effects (execution of a function whenever the mock object is called) instead of simple return values. For instance, we can raise an exception to make sure your code is robust enough when a method is called.

The only thing to do is assign to side_effect property of mock object the desired effect.

@patch(“upload_service.publish_file”)
def test_publish_new_file_error(mock_publish_file):
    mock_publish_file.side_effect = RuntimeError(“something bad happened during upload”)

    old_path="/user/file1.txt"
    new_file_path="/user/file2.txt"

    existing_file_object = get_file_identified_by_path(old_path)

    upload_service.upload_and_publish_file(existing_file_object, new_file_path)

    assertRaises(RuntimeError, upload_service.publish_file, existing_file_object, new_file_path)

    assertEquals(existing_file_object.path, old_path)
    assertFalse(file_helpers.exist_file(new_file_path))

    # other necessary assertions
    …

With the previous test, we make sure if an error happens during publishing of a file, it is discarded and it is not in our system.

Leave a Comment

¿Necesitas una estimación?

Calcula ahora