2013-05-24 5 views
4

Возможно ли идентифицировать родительский экземпляр макетного объекта экземпляра дочернего макета или дочерний экземпляр родительского макета? Например, если у меня есть следующий кодНайти родительский макет объекта для ребенка, дочерние макеты объектов родителя

>>> from unittest.mock import MagicMock 
>>> parent_mock = MagicMock() 
>>> child_mock1 = parent_mock(a=1) 
>>> child_mock2 = parent_mock(b='spam') 

Как я мог подтвердить позже, что ребенок издевается порожден от вызова parent_mock? Как я могу проверить, какие макетные объекты parent_mock?

Кроме того, как я мог различить, что child_mock1 возникла именно из вызова parent_mock(a=1), в то время как child_mock2 происходит от вызова parent_mock(b='spam')?

Я понимаю, что это может быть manually attach mocks as attributes of other mocks, однако для этого требуется много настроек, так что вам нужно будет явно определить обратные вызовы родительского макета, чтобы он возвращал назначенные дочерние mocks, и поэтому он не делает 't масштабируется задолго до нескольких звонков.

+0

Возможно, вы вообще не хотите делать что-то подобное. Это не pythonic, чтобы беспокоиться о иерархиях наследования. Почему вы хотите знать эти вещи? Вероятно, есть другой способ решить вашу актуальную проблему. – erikbwork

+2

@ erikb85 Слова «родитель» и «ребенок» не означают «суперкласс» и «подкласс». Экземпляры 'Mock', когда вызывается, возвращают« дочерние »экземпляры' Mock' (по умолчанию); экземпляр 'Mock', который создал другой, называется« родителем ». – gotgenes

+0

Что не отвечает на вопрос.:) – erikbwork

ответ

1

Как я могу подтвердить позже, что ребенок издевается от вызова parent_mock?

Ну, есть недокументированная атрибут _mock_new_parent, который можно использовать, как это ...

>>> from unittest.mock import MagicMock 
>>> parent_mock = MagicMock() 
>>> child_mock1 = parent_mock(a=1) 
>>> child_mock2 = parent_mock(b='spam') 
>>> child_mock1._mock_new_parent is parent_mock 
True 
>>> child_mock2._mock_new_parent is parent_mock 
True 

... но это выглядит, как если бы ответ на все ваши другие вопросы есть «вы можете» т».

Я полагаю, вы могли бы подкласс MagicMock, чтобы следить за своими детьми с чем-то вроде этого ...

class MyMock(MagicMock): 

    def __init__(self, *args, **kwargs): 
     MagicMock.__init__(self, *args, **kwargs) 
     self._kids = [] 

    def __call__(self, *args, **kwargs): 
     result = MagicMock.__call__(self, *args, **kwargs) 
     self._kids.append((args, kwargs, result)) 
     return result 

... тогда вы могли бы сделать ...

>>> parent_mock = MyMock() 
>>> child_mock1 = parent_mock(a=1) 
>>> child_mock2 = parent_mock(b='spam') 
>>> parent_mock._kids 
[((), {'a': 1}, <MyMock name='mock()' id='140358357513616'>), 
((), {'b': 'spam'}, <MyMock name='mock()' id='140358357513616'>)] 
>>> parent_mock._kids[0][2] is child_mock1 
True 
>>> parent_mock._kids[1][2] is child_mock2 
True 
+0

У вашего 'MyMock' все еще есть' child_mock1 is child_mock2', потому что вы делегируете 'MagicMock .__ call__', который не будет создавать разные объекты для разных вызовов. Вы не можете отличить, из какого звона пришло издевательство. – user2357112

1

Тщательное там!

26.4.2.1. Calling

Фиктивные объекты могут быть отозваны. Вызов возвращает значение, заданное как атрибут return_value. Возвращаемое значение по умолчанию - новый объект Mock; он создается при первом обращении к возвращаемому значению (либо явно, либо путем вызова Mock), но он сохраняется и тот же, который возвращается каждый раз.

Если вы хотите, чтобы разные вызовы дали разные результаты, вы должны дать свой макет атрибуту side_effect. Если mock.side_effect является функцией, то mock(*args, **kwargs) вызовет mock.side_effect(*args, **kwargs) и вернет то, что возвращается. Вы можете сделать свой обычай mock.side_effect отслеживать, какие вызовы вызывают какие значения.

+0

Я пропустил эту часть документации, спасибо! Похоже, что реализация @ Aya, которая подклассифицирует «MagicMock» и переопределяет «__call__», фактически вернет отдельные макеты. – gotgenes

+0

Реализация Aya не работает. Он делегирует 'MagicMock .__ call__', который всегда возвращает тот же объект. Другими словами, 'child_mock1 является child_mock2'. – user2357112

Смежные вопросы