Reputation: 7928
Not an expert. If I patch a module's method, is it possible to re-use the same patch in other methods of the TestCase?
def load(**kwargs):
return 1
def load2(**kwargs):
return2
@patch.multiple('module',
get_data=MagicMock(side_effect=load),
headers=MagicMock(return_value=""))
def test_get_some_method(self):
# here is ok
@patch.multiple('module',
get_data=MagicMock(side_effect=load2),
headers=MagicMock(return_value=""))
def test_get_other_method(self):
# here I get an exception:'load1() takes 0 positional arguments but 1 was given'
EDIT
Maybe it is better to use return_value
instead of side_effect...
Upvotes: 0
Views: 77
Reputation: 7928
Based on the Daniil'answer, maybe something like this:
class TestCase(unittest.TestCase):
def setUp(self):
self.patcher = patch.multiple('lib.MyClass',
get_data=MagicMock(side_effect=load),
headers=MagicMock(return_value="")).start()
self.my_module = MyClass()
def test_something(self):
_ = self.my_module.get_data()
Upvotes: 0
Reputation: 18458
Yes, you can use the TestCase.setUpClass
class method for this. The "patcher" returned by patch
needs to be properly stopped though, if you don't use it in the form of a decorator or context manager. Thus you should always include that call in TestCase.tearDownClass
.
Here is a little demo for you.
code.py
class Spam:
def __init__(self, x: float) -> None:
self._x = x
def get_x(self) -> float:
return self._x
def get_x_times_2(self) -> float:
return self.get_x() * 2
def get_x_squared(self) -> float:
return self.get_x() ** 2
def print_x(self) -> None:
print(self.get_x())
Say we wanted to test all methods that call get_x
and with the exact same mock object (for some reason).
test.py
from unittest import TestCase
from unittest.mock import MagicMock, patch
from . import code
class SpamTestCase(TestCase):
get_x_patcher = None
mock_get_x: MagicMock = None
@classmethod
def setUpClass(cls) -> None:
cls.get_x_patcher = patch.object(code.Spam, "get_x")
cls.mock_get_x = cls.get_x_patcher.start()
@classmethod
def tearDownClass(cls) -> None:
cls.get_x_patcher.stop()
def setUp(self) -> None:
self.spam = code.Spam(3.14)
def test_get_x_times_2(self) -> None:
self.mock_get_x.return_value = 5
self.assertEqual(10, self.spam.get_x_times_2())
def test_get_x_squared(self) -> None:
self.mock_get_x.return_value = 4
self.assertEqual(16, self.spam.get_x_squared())
@patch.object(code, "print")
def test_print_x(self, mock_print: MagicMock) -> None:
self.mock_get_x.return_value = 10.5
self.assertIsNone(self.spam.print_x())
mock_print.assert_called_once_with(10.5)
However, I don't really see the use case for this. Using regular setUp
and tearDown
should be enough to facilitate consistency across all test methods, if you need that and don't want to repeat yourself in multiple decorators/context managers. The mock objects will not be literally the same, but created the same way.
Hope this helps.
Upvotes: 1