Reputation: 543
I have a file my_work.py
. The class MyModel
is used inside of the class MyWork
's run
method. Suppose the functionality of MyModel
is well tested by its own dedicated unit-tests. My focus is to test if MyModel
is used properly inside MyWork
.
I need to test 2 things:
MyModel
is instantiated with given arguments.MyModel.run
method is called. Because it is a long and expensive process, I have to mock it with fake returns.Note that, both classes MyModel
and MyWork
are defined in the same file my_work.py
. This is just an example for this post. In my real application, they are defined in different py-files. Not sure if this can make a difference or not.
I have tried myself to write unit-test for it, but I could not make it. Could you please help me? See my test file test_my_work.py
. Thanks a lot in advance!
This is the file: my_work.py
.
from typing import Tuple
class MyModel:
def __init__(self, a: float, b: str):
self._a = a
self._b = b
def run(self) -> Tuple[float, float]:
# some long and expensive calculation.
return self._a + 1, self._a + 2
class MyWork:
def __init__(self, name: str):
self._name = name
self._res_1: float = 0
self._res_2: float = 0
def run(self) -> Tuple[float, float]:
a = 2.5
b = self._name
model = MyModel(a=a, b=b)
res_1, res_2 = model.run()
return res_1, res_2
And this is the file: test_my_work.py
.
import unittest
from unittest.mock import patch
from my_work import MyModel, MyWork
class TestMyWork(unittest.TestCase):
@patch.object(MyModel, 'run', return_value=(3.5, 4.5))
def test_if_my_model_run_is_called_in_my_work_run(self, mocked_run):
self._my_work = MyWork(name='XX')
self._my_work.run()
mocked_run.assert_called_once()
@patch.object(MyModel, '__init__')
def test_if_my_model_is_initiated_in_my_work_run(self, mocked_init):
self._my_work = MyWork(name='XX')
self._my_work.run()
mocked_init.assert_called_once_with(a=2.5, b='XX')
if __name__ == '__main__':
unittest.main()
Upvotes: 0
Views: 523
Reputation: 11414
I would recommend to rather use the patch
method instead of patch.object
because MagicMock
does not support mocking the __init__
method.
For the patch
method, you'll need the "target" path to your class. In this case it will be 'my_work.MyModel'
.
If you patch your model like this:
@patch('my_work.MyModel')
def test_if_my_model_is_initiated_in_my_work_run(self, my_model_mock):
...
Then my_model_mock
will be a mock of the class MyModel
and will be replaced with MagicMock
.
my_model.return_value
will be called when a new instance of MyModel
is called. The run
method can then be mocked like this:
my_model_mock.return_value.run.return_value = (3.5, 4.5)
Upvotes: 1