In this sentence
explain. In Python3, MagicMock is included in the standard module unittest.mock.
In Python2, you can use it by installing the mock package with pip install mock
.
Start the Python interpreter and create a MagicMock object
$ python3.6
Python 3.6.0 (default, Feb 27 2017, 00:03:01)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from unittest.mock import MagicMock
>>> f = MagicMock()
I assume that this f
is a function and try to call it
>>> f(1)
<MagicMock name='mock()' id='4381867704'>
I can call it even though I didn't define it as a function. that's strange. The return value is also MagicMock, but I do not care about that and I will call it further
>>> f(2)
<MagicMock name='mock()' id='4381867704'>
>>> f(1, 2, 3)
<MagicMock name='mock()' id='4381867704'>
I could call it freely even if I changed the value of the argument and the number of arguments. I'm surprised. If you try to evaluate f.call_args_list
here,
>>> f.call_args_list
[call(1), call(2), call(1, 2, 3)]
I've called it three times since I created MagicMock. You can see that it is recorded with the arguments. it's interesting.
This is not the only feature of MagicMock. Let's create a MagicMock instance again, set the value to f.return_value
, and then call f
.
>>> f = MagicMock()
>>> f.return_value = 5
>>> f(1, 2)
5
>>> f(1)
5
>>> f()
5
No matter what argument you give, the set value will be returned. In this way you can replace the return value of the function with any value you like. In this case as well, how the call was made is recorded.
>>> f.call_args_list
[call(1, 2), call(1), call()]
There are other features, but let's leave this out for now and see how they can help.
Suppose you have a function push_if_even ()
that takes an integer, calls push ()
if it's even, and does nothing if it's odd.
Specifically, the code is as follows.
def push():
pass
def push_if_even(x):
"""Receives an integer, push if even()Call"""
if x % 2 == 0:
push()
Now suppose you want to write a test to see if this code is implemented correctly. As we saw earlier, MagicMock keeps a record of what was called as a function, so we take advantage of that. You can test it by doing the following:
from unittest.mock import MagicMock
push = MagicMock()
push_if_even(1)
assert len(push.call_args_list) == 0
push = MagicMock()
push_if_even(0)
assert len(push.call_args_list) == 1
print("success")
You can also write as follows
push = MagicMock()
push_if_even(1)
push.asset_not_called()
push = MagicMock()
push_if_even(0)
push.assert_called_once()
Let's take a look at what happens when assert fails.
>>> from unittest.mock import MagicMock
>>> push = MagicMock()
>>> push.assert_called_once()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 795, in assert_called_once
raise AssertionError(msg)
AssertionError: Expected 'mock' to have been called once. Called 0 times.
>>> push()
<MagicMock name='mock()' id='4356157392'>
>>> push.assert_not_called()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 777, in assert_not_called
raise AssertionError(msg)
AssertionError: Expected 'mock' to not have been called. Called 1 times.
A function that returns True if today is Sunday, False otherwise ʻis_sunday`
from datetime import date
def today():
return date.today()
def is_sunday():
return today().weekday() == 6
Suppose you want to test that is working properly. If today isn't Sunday, you can call it once and see that it returns False, then wait for the next Sunday and call it again to see that it returns True. However, it will take days to finish the test. If you can't wait for that, use MagicMock's ability to control the return value.
from unittest.mock import MagicMock
today = MagicMock()
today.return_value = date(2020, 2, 1)
assert is_sunday() == False
today = MagicMock()
today.return_value = date(2020, 2, 2)
assert is_sunday() == True
print("success")
If so, you can test it in an instant. It's convenient.
After seeing the nature of MagicMock,
I implemented the test code by utilizing the function of. Testing for functions that affect or are affected by the environment is more difficult to write than testing simple functions, but you can mock the impact on the environment or stub the impact from the environment. We've seen how easy it is to create reproducible test code by replacing it.
In this example, I simply overwrote the function, but the mock module has a handy thing called patch, which makes it easy to replace the function only during the test and then restore it. Use it when writing tests.
Recommended Posts