[Python] pytest-mock Usage notes

Installation

It's easy if you use poetry.

poetry add -D pytest-mock

It's easy even if you're not using it. However, poetry is recommended.

python


pip install pytest-mock
```

# How to write a test

 Specify `mocker` as an argument of the test method.

```python
class MyClassTests:
    def test_something(self, mocker):
        pass
```

# How to make a mock

 There are two ways to create a [mock --Mock](https://docs.python.org/ja/3/library/unittest.mock.html#the-mock-class), one is to use `mocker.Mock` to create an instance, and the other is to use` mocker.patch` to dynamically replace it with a Mock instance.

 Suppose you have a module like this as a subject.

```
exmock
├── __init__.py
├── bar.py
├── foo.py
└── target.py
```



#### **`exmock/target.py`**
```python

from .foo import FooClass
from .bar import BarClass


class TargetClass:
    def do_something(self, foo: FooClass) -> None:
        """ do_foo()Do the result of_bar()Pass to."""
        bar = BarClass()
        bar.do_bar(foo.do_foo())
```

## Make a class mock

```python
foo_mock = mocker.Mock(spec=FooClass)
# foo_mock.do_foo is also a mock.
```

 By specifying the class as spec, only the attributes that actually exist in the class will grow.
 The attributes that have grown are also instances of `Mock`.



## Mock the return value of the constructor

 The constructor doesn't return a value. It's strange as an expression, but for convenience of explanation, it's done like this.

```python
bar_mock = mocker.Mock(spec=BarClass)
mocker.patch('exmock.target.BarClass', return_value=bar_mock)
```

 The `exmock.target.BarClass` is patched to match the` from .bar import BarClass` in the test target file ** exmock/target.py **.

## Mock the method

```python
do_bar_mock = mocker.patch.object(BarClass, 'do_bar')
```

 The implementation of the `do_bar` method is mocked and nothing happens.

 To change the behavior of the `do_bar` method, use the return mock.

# Change the behavior of the mock

 The generated mock can be moved arbitrarily according to the test.

## Set the return value

 Set the value in the `return_value` attribute of the generated mock.

```python
mymock.return_value =Return value
```

## Set the return value of the property

 It is OK if you set the value directly.

```python
mymock.foo =Return value
```

## Raise an exception when called

 Set an exception to the `side_effect` attribute of the generated mock.

```python
mymock.side_effect = Exception('It is an error')
```

## Replace completely

 It completely replaces the mocked implementation.

```python
def side_effect():
    pass

mymock.side_effect = side_effect
```

# Mock test

 Test that something has been done to the mock.

## Test that it was called once

```python
mymock.assert_called_once()
```

## Test that it was called multiple times

```python
#If you are using pytest.
assert mymock.call_count ==Number of times
```

## Test that it is not called at all

```python
mymock.assert_not_called()
```

## Test that it was called with a specific argument

```python
mymock.assert_called_with(Specific argument 1,Specific argument 2, ……)
mymock.assert_called_once_with(Specific argument 1,Specific argument 2, ……) #When called once
```

## Test complex arguments

```python
args, kwargs = mymock.call_args
#Test args and kwargs
```

 `call_args` contains the most recent call argument.
 `args` is a tuple that contains non-keyword arguments. `kwargs` is a dictionary that contains arguments with keywords.



# Verification environment

 This is the environment I used to write this article.

* Python 3.8.2
* Poetry 1.1.4
* pytest-mock 3.4.0

 I put the used files here.
https://github.com/sengokyu/python-pytest-mock-usage-example


Recommended Posts

[Python] pytest-mock Usage notes
python decorator usage notes
Python standard unittest usage notes
python * args, ** kwargs Usage notes
Python scraping notes
Python study notes _000
Python learning notes
Python beginner notes
Python study notes_006
python C ++ notes
Python study notes _005
Python grammar notes
Python Library notes
python personal notes
python pandas notes
Python study notes_001
python learning notes
Python3.4 installation notes
missingintegers python personal notes
Python package development notes
Usage of Python locals ()
Python ipaddress package notes
[Personal notes] Python, Django
Python Pickle format notes
First Python miscellaneous notes
Matlab => Python migration notes
Notes around Python3 assignments
Notes using Python subprocesses
Python try / except notes
Python framework bottle notes
Python notes using perl-ternary operator
[Python] Correct usage of map
O'Reilly python3 Primer Learning Notes
Web scraping notes in python3
Python notes to forget soon
Python notes using perl-special variables
Python 處 處 regular expression Notes
Python Tkinter notes (for myself)
[Python] Notes on data analysis
Python data analysis learning notes
Notes on installing Python on Mac
Sample usage of Python pickle
Basic usage of Python f-string
Get Evernote notes in Python
[Python] Correct usage of join
Notes on installing Python on CentOS
Notes on Python and dictionary types
Python
Minimum grammar notes for writing Python
Personal notes for python image processing
Python Pandas Data Preprocessing Personal Notes
Typing automation notes by Python beginners
Notes for me python csv graph
Notes on installing Python using PyEnv
Elementary ITK usage learned in Python
Notes for Python file input / output
Notes on using rstrip with python.
Notes on accessing dashDB from python
[python] Correct usage of if statement
(Personal notes) Python metaclasses and metaprogramming
Notes for using OpenCV on Windows10 Python 3.8.3.