2015-04-07 1 views
1

У меня есть класс, который мне нужно исправить, который работает подобно этомуподклассы MagicMock в питоне

class Foo(object): 
    def __init__(self, query): 
     self._query = query 

    def do_stuff(self): 
     # do stuff with self._query 

Как бы я создал класс насмешливого для Foo таким образом, что

foo = MockFoo(query) 
foo.do_stuff() 

возвращает mock result, но все же принимая во внимание данные, переданные для query. Я думал о подклассов MagicMock как этот

class MockFoo(MagicMock): 
    def __init__(self, query, *args, **kwargs): 
     super(MagicMock, self).__init__(*args, **kwargs) 
     self._query 

    def do_stuff(self): 
     mock_result = self._query * 10 
     return MagicMock(return_value=mock_result) 

, но я не могу вполне понять, как применить patch использовать MockFoo вместо MagicMock в реальной TestCase. Мне нужно написать тест, подобный этому.

with patch('x.Foo') as mock_foo: 
    # run test code 
    self.assertTrue(mock_foo.called) 
    self.assertEqual(mock_foo.wait.return_value, 20) 

Я знаю, что я могу просто использовать простой MagicMock с autospec=True или что-то и переопределить возвращаемые значения для каждого из методов, но было бы неплохо иметь макет класс, который я могу просто использовать, чтобы заменить класс производства за один присест. Ключевым битом является доступ к переменной-члену self._query в методах макета, при этом он инициализируется в конструкторе (как и производственный класс).

+0

Я не думаю, что это работает, потому что на каком-то уровне вам нужно различать реальные методы/свойства и издевавшиеся методы/свойства. Такие вещи, как «called» и «return_value», являются частью макета, поэтому не представляется возможным добавить их в модифицированный экземпляр производственного класса. Я думаю, что лучше делать то, что вы сказали, насмехаясь над тем, что вам нужно, и, возможно, добавьте вспомогательный код для этого. –

ответ

1

О вас базовый вопрос ответ использовать new_callable параметр в patch:

with patch('x.Foo', new_callable=MockFoo) as mock_foo: 
    # run test code 
    self.assertTrue(mock_foo.called) 
    self.assertEqual(mock_foo.wait.return_value, 20) 

Если вам нужно добавить аргумент MockFoo INIT называть считают, что каждый аргумент не используется в patch будет passet в макете конструктора (MockFoo в вашем случае).

Если вам нужна обертка вашего производственного класса, возможно, вы ищете не то место: макет не является оберткой.

Когда вы издеваетесь над чем-то, вы действительно не хотите знать, как ваш макет выполняет эту работу, а только то, как ваш код использует его и как вы кодируете реакцию на издевательства над объектами.