Python unittest: to mock.patch () или просто заменить метод с помощью Mock?

Когда насмешливые классы или методы при написании unittests в Python, зачем мне использовать декоратор @patch ? Я просто мог заменить метод с помощью объекта Mock без аннотации патча.

Примеры:

class TestFoobar(unittest.TestCase): def setUp(self): self.foobar = FooBar() # 1) With patch decorator: @patch.object(FooBar, "_get_bar") @patch.object(FooBar, "_get_foo") def test_get_foobar_with_patch(self, mock_get_foo, mock_get_bar): mock_get_bar.return_value = "bar1" mock_get_foo.return_value = "foo1" actual = self.foobar.get_foobar() self.assertEqual("foo1bar1", actual) # 2) Just replacing the real methods with Mock with proper return_value: def test_get_foobar_with_replacement(self): self.foobar._get_foo = Mock(return_value="foo2") self.foobar._get_bar = Mock(return_value="bar2") actual = self.foobar.get_foobar() self.assertEqual("foo2bar2", actual) 

Может ли кто-нибудь привести пример, где исправитель патча хорош и замена плохо?

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

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

Я попытался доказать это, но пришел пустым: оба теста проходят в следующем коде:

 def test_get_foobar_with_replacement(self): self.foobar._get_foo = Mock(return_value="foo2") self.foobar._get_bar = Mock(return_value="bar2") actual = self.foobar.get_foobar() self.assertIsInstance(self.foobar._get_bar, Mock) self.assertIsInstance(self.foobar._get_foo, Mock) self.assertEqual("foo2bar2", actual) def test_get_foobar_with_real_methods(self): actual = self.foobar.get_foobar() self.assertNotIsInstance(self.foobar._get_bar, Mock) self.assertNotIsInstance(self.foobar._get_foo, Mock) self.assertIsInstance(self.foobar._get_bar, types.MethodType) self.assertIsInstance(self.foobar._get_foo, types.MethodType) self.assertEqual("foobar", actual) 

Полный исходный код (Python 3.3): dropbox.com/s/t8bewsdaalzrgke/test_foobar.py?dl=0

patch.object восстановит элемент, который вы исправили до исходного состояния после возврата метода теста. Если вы обезвреживаете объект самостоятельно, вам нужно восстановить исходное значение, если этот объект будет использоваться в другом тесте.

В ваших двух примерах вы фактически исправляете две разные вещи. Ваш вызов patch.object исправляет класс FooBar , в то время как ваш патч обезьяны исправляет определенный экземпляр FooBar .

Восстановление исходного объекта не имеет значения, если объект будет создаваться с нуля каждый раз. (Вы не показываете его, но я предполагаю, что self.foobar создается в методе setUp , так что, даже если вы замените его метод _get_foo , вы не повторно используете этот конкретный объект в нескольких тестах.)