How deep should I mock dependencies in unit tests

Consider the following function:

def get_api_status(api_client):
    response = api_client.get('/status/')
    return response.content

and the test for it:

def test_get_api_status():
    mocked_api_client = MagicMock()  # depth 0
    mocked_response = MagicMock()  # depth 1
    mocked_response.status = 'ok'  # depth 1.1
    mocked_api_client.get = MagicMock(return_value=mocked_response)  # depth 0.1
    assert get_api_status(mocked_api_client) == 'ok'

The above example is really simple but you can see the pattern. What if the response.content would also have method get_data which would have the method get_raw_bytes? The question is: “when does code start to smell?”.

My assumptions:

  1. Let’s say api_client is here to reduce coupling. api_client in real life is subclassed either http_client or filesystem_client.
  2. api_client.get does always return api_response which has .content attribute.

My thoughts:

I suspect the problem is either:

  • The example is fine. It’s the maximal level of complexity. If api_response.content would really have also the method get_data and the function get_api_status would use it then it should be recognised as wrong design.
  • tight coupling between get_api_status and the api_client abstract – do I need to make one more abstract??

2

IMHO we gave to distinguish between dependencies (other code that provides behavior) and Data Transfer Objects / Value Objects .

DTOs

This code primary hold data and have at most very simple logic, if at all, and does not have Dependencies (references to code of the other type) themselves.
I would not mock DTOs (like response in your example) as well as any collection. DTOs and collections are cheap to construct. And when you need to configure them some levels deep you couldn’t come around that by mocking anyway.

Dependencies

This is other code that provides behavior.
There should be no need to mock Dependencies beyond one level dept. Some times we need to dive one level down because the direct dependency is a factory. If you find that one level down is not enough you might think al little about your design…

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *