Intro
Mock is a very useful package for unittest in python. It can replace some classes or functions and change their behaviors, it can also use some built-in methods to help you assert whether pytest calls certain part of your code.
Mock() & MagicMock()
For simplicity, let’s use Mock for example. In most cases, Mock and MagicMock are the same :)
Mock is a class that create all attributes and methods as you access them and store details of how they have been used.
What’s more, you can set anything to a Mock, it will treat them as new Mock (sub Mock).
1 | # set an undefined method to a Mock |
return_value
By setting some methods or functions as Mock, then setting return_value can change original logic: I don’t care about what you write in the function, just return what I want!
1 | class Object: |
This is always useful in unittest, like:
- I don’t want to send a real request via network, just let the requester / dispatcher return what I want;
- I don’t want to access a real DB, just tell me what data you have;
1 | class MySvc: |
Sometimes, we will meet some call chains, such as mock.connection.cursor().execute(...).
1 | # mock.call1().call2().call3() |
Basically, we can change the code as following
1
2
3
4
5
6 m = Mock()
c1 = Mock()
m.call1.return_value = c1
c2 = Mock()
c1.call2.return_value = c2
c2.call3.return_value = "foo"
side_effect
side_effect = Exception
1 | >> m = Mock() |
side_effect = iterable
If we set iterable to side_effect, every time we call it, it will yield one element.
1 | >> m = Mock() |
side_effect = callable
1 | def log(*args, **kwargs): |
When we set both return_value and side_effect, the Mock will only use side_effect!!
spec & spec_set
spec can be either a list of string or an existing class / instance. After we set spec, the mock can only have corresponding attributes and methods (just like we use dir to see what attributes and methods does one class support).
1 | class Object: |
The difference between spec and spec_set is, spec can add new stuff while spec_set can only read.
1 | m = Mock(spec = ["one"]) |
assertion & call args
Mock supports lots of assertions, such as assert_called, assert_called_once, assert_called_with, etc.
1 | m = Mock() |
Mock can also remember what args you used via call_args or call_args_list.
1 | m = Mock() |
What’s the difference between these two?
So you can simply think MagicMock = Mock with pre-defined magic methods.
1 | >> len(Mock()) |
So if you want to test or use magic methods in your test, use MagicMock.
If you want to modify the magic methods or just for simplicity purpose, plz use Mock.