Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid type warnings when mocking objects in unit tests?

Assuming I have a function that takes a complex object and does something with it:

def foo(bar: SomeComplexObject):
    ...

In unit tests bar will be replaced by a mock object, but that of courses now raises type warnings. Should I simply ignore or suppress these or is there a proper way to deal with them (without changing the original function signature of course)?

Update: I've seen now that this is an open issue on mypy, but its been in that state for over two years. Has any consensus emerged on how to work around this?

like image 505
gmolau Avatar asked May 16 '18 05:05

gmolau


People also ask

Is mocking bad in unit testing?

Mocking is a very common testing mechanism, and it is a bad idea. This post details why you should not use mocking, and why and how you should write integration tests instead. TL;DR: Mocking provides false confidence by hiding real failures.

What should be mocked in unit tests?

Mocking is used in unit tests to replace the return value of a class method or function. This may seem counterintuitive since unit tests are supposed to test the class method or function, but we are replacing all those processing and setting a predefined output.

What's true about mocking in a unit test?

Mocking is a process used in unit testing when the unit being tested has external dependencies. The purpose of mocking is to isolate and focus on the code being tested and not on the behavior or state of external dependencies.


1 Answers

I'm going to put my 2¢ in and say that you should type-check your testsuite. Its still code and static type checking will help you write better code faster.

That leaves the question of how. Ideally, if your function expects SomeComplexObject then you also pass in an instance thereof. Either by building one in your test fixtures, or by subclassing and overriding what you don't need. The best unit test is the one that operates on proper input.

That still leaves the case where this is impractical or we explicitly want to test how invalid input is handled. In that case just explicitly cast your mock to the type that mypy requires:

from typing import cast

def test_foo():
    mock_bar = cast(SomeComplexObject, MockBar())
    foo(mock_bar)
like image 193
vbraun Avatar answered Sep 21 '22 10:09

vbraun