Python unit tests: a good trick about mocking

Ben-Hur Santos Ott
3 min readAug 12, 2019

Hi everyone!

Today we will learn an easier way to work with mocks in our python code. How to mock dependencies no matter if they are variables, classes, functions are imports.

To help us, let’s create a simple scenario:

We will have a use case to register a new user. After validating the e-mail and the password, we will save the user to the database and send a welcome e-mail.

Creating the Code

The implementation of our create_user function will be:

We have two important things here to mock:

1 — Save the user in DB:

def _create_user_in_db(email, password):
user = User(
email=email,
password=_hash_password(password)
)

user.save_in_db() # <<<< THIS FUNCTION

return user

2 — Send the email

def _send_welcome_email(user):
send_email( # <<<< THIS FUNCTION
message='Welcome!',
from_addr='admin@email.com',
to_addrs=[user.email]
)

In the first case, the save_in_db is an object instance function. The second is an imported function from another file.

Creating the Test Case

First, let’s create the base file for our tests:

We have our unit test with the given scenario.

Solving the first problem: the save_user_in_db

This one is easy and have tons of documentation in the internet.

You just need to patch the method in User class:

In this solution, we are defining:

with patch.object(User, 'save_in_db', user_save_in_db_mock)

No matter where, if I call the method save_in_db (second arg) of the User class (first arg), instead of executing the real method, use the mock (third arg).

After this, we can validate if the mock was called:

self.assertEqual(
1,
user_save_in_db_mock.call_count
)

Solving the second problem: the send_email

Abstracting the context, we have: a function that is imported from another file.

from send_email import send_email

And HERE IS THE TRICK!

Most of the tutorials in the internet tells you to mock the function using the path of file, like:

patch('send_email.send_email', my_mock)

But when your mock have a complex path, it’s not so easy to remember all the time how to mock this dependency.

An easier way to mock the send_email function is to use the path of the function you are testing !

Take a look at this line:

patch(f'{create_user.__module__}.send_email', send_email_mock)

This is: in the module of the create_user , replace the send_email with the mock.

You can use this trick to mock class, variables, functions, practically anything:

create_user.py

my_variable = 5def create_user(email, password):
_validate_email(email)
_validate_password(password)

print(my_variable)

user = _create_user_in_db(email, password)

_send_welcome_email(user)

create_user_tests.py

patch(f'{create_user.__module__}.my_variable', 'foo')

result:

Conclusion

Mocking local dependencies is easy but unfortunately barely explored or explained.

You just need to remember one thing: f'{my_module_func.__module__}.dep_name’

And everything will be easier =)

See you o/

--

--