Здравствуйте!
Tl; dr : мне нужно проверить, что метод открытого класса вызывает методы частного класса в определенном порядке, в зависимости от некоторых условий.Как я могу это сделать?
Учитывая наличие такого класса:
class SomeClass(object):
def __init__(self, param: ParamsEnum):
self._param = param
def process(self):
if self._param == ParamsEnum.VALUE_1:
self._do_intermediate_process()
self._do_process()
def _do_process(self):
raise NotImplementedError
def _do_intermediate_process(self):
pass
Я хочу написать модульный тест для проверки этой логики процесса.Я пробовал несколько подходов, но ни один из них не удался.
Подход один - с использованием отдельного Mock () в качестве контейнера.
@mock.patch.object(SomeClass, '_do_process')
@mock.patch.object(SomeClass, '_do_intermediate_process')
def test_process(self, mocked_do_process, mocked_do_intermediate_process):
mock_container = Mock()
mock_container.m0, mock_container.m1 = mocked_do_process, mocked_do_intermediate_process
instance = SomeClass(ParamsEnum.VALUE_1)
instance.process()
mocked_do_process.assert_called_once()
mocked_do_intermediate_process.assert_called_once()
mock_container.assert_has_calls([mock_container.m0, mock_container.m1])
В результате mock_container.method_calls
ничего не показывает.
Приближается два - насмешливый «процесс» с сохранением оригинальной логики в качестве побочного эффекта.Этот тест проходит независимо от порядка смоделированных методов в последней строке.
@mock.patch.object(SomeClass, '_do_process')
@mock.patch.object(SomeClass, '_do_intermediate_process')
def test_process(self, mocked_do_process, mocked_do_intermediate_process):
origignal_process = SomeClass.process
with mock.patch.object(SomeClass, 'process', autospec=True) as mocked_process:
def side_effect(self):
return origignal_process(self)
mocked_process.side_effect = side_effect
class_mock = Mock(spec=SomeClass, autospec=True)
class_mock.process = mocked_process
class_mock._do_process = mocked_do_process
class_mock._do_intermediate_process = mocked_do_intermediate_process
class_mock._param = ParamsEnum.VALUE_1
class_mock.process(class_mock)
mocked_do_process.assert_called_once()
mocked_do_intermediate_process.assert_called_once()
mocked_process.assert_called_once()
class_mock.assert_has_calls([mocked_do_intermediate_process, mocked_do_process])