I'm trying to unit test a class, let's call it A. As part of A's instantiation, it tries to create instances of many classes from a package external.
from external import B, C, D
class A
def __init__(self, some_config):
b_config, c_config, d_config = self._generate_config(some_config)
b = B(b_config)
c = C(c_config)
d = D(d_config)
I don't want to instantiate anything from external for my unit test, but the nature of the codebase is that I also don't want to pass b, c, or d in as external arguments for the constructor.
I know using mock.patch, I can write a test
@mock.patch(external.D, autospec=True)
@mock.patch(external.C, autospec=True)
@mock.patch(external.B, autospec=True)
def test(self, b_patch: mock.MagicMock,
c_patch: mock.MagicMock,
d_patch: mock.MagicMock):
b_patch.return_value = mock.Mock()
c_patch.return_value = mock.Mock()
d_patch.return_value = mock.Mock()
test_a = A()
# Assert no problems with instantiating A
# AKA self._generate_config worked
But is there an easy way to mark all classes inside external
such that they should be mocked like above?
CodePudding user response:
Your sample code isn't self-consistent -- in your first example you're doing from external import B
and in the second example it looks like you did import external
. In the second form you're able to just patch external
:
import external
class A:
def __init__(self):
b = external.B()
c = external.C()
d = external.D()
from unittest.mock import patch
@patch('__main__.external')
def test(mock_external):
test_a = A()
test()
The above test passes regardless of the contents of external.py
(as long as it doesn't raise an error on the initial import) because the test patches out the entire module.
It's not necessary to individually assign all the different attributes of external
to Mock
objects because every attribute of a Mock
is already an auto-created Mock
unless you set it to something else.
If there is no external
name in the module under test (because you did from external import B
etc) you need to individually patch the B
, C
, and D
names.