简体   繁体   English

Python unittest:到mock.patch()或只是用Mock替换方法?

[英]Python unittest: to mock.patch() or just replace method with Mock?

When mocking classes or methods when writing unittests in Python, why do I need to use @patch decorator? 在Python中编写单元测试时模拟类或方法时,为什么需要使用@patch装饰器? I just could replace the method with Mock object without any patch annotation. 我只是可以用Mock对象替换方法而不需要任何补丁注释。

Examples: 例子:

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)

Could someone produce an example, where patch decorator is good and replacing is bad? 有人可以制作一个例子,其中补丁装饰器是好的,替换是坏的吗?

We have always used patch decorator with our team, but after reading this comment for a post, I got the idea that maybe we could write nicer-looking code without the need of patch decorators. 我们总是在我们的团队中使用补丁装饰器,但在阅读了这篇帖子的评论之后,我认为可能我们可以编写更好看的代码而无需补丁装饰器。

I understand that patching is temporary, so maybe with some cases, it is dangerous to not use patch decorator and replace methods with mock instead? 我知道修补是暂时的,所以也许在某些情况下,不使用补丁修饰器并用mock替换方法是危险的? Could it be that replacing objects in one test method can affect the result of the next test method? 可能是在一个测试方法中替换对象会影响下一个测试方法的结果吗?

I tried to prove this, but came up empty: both tests pass in the next code: 我试图证明这一点,但是空了:两个测试都传递到下一个代码中:

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)

Full source code (Python 3.3): dropbox.com/s/t8bewsdaalzrgke/test_foobar.py?dl=0 完整源代码(Python 3.3):dropbox.com/s/t8bewsdaalzrgke/test_foobar.py?dl=0

patch.object will restore the item you patched to its original state after the test method returns. patch.object将在测试方法返回后将您修补的项目恢复到其原始状态。 If you monkey-patch the object yourself, you need to restore the original value if that object will be used in another test. 如果您自己修补对象,则需要恢复原始值(如果该对象将在另一个测试中使用)。

In your two examples, you are actually patching two different things. 在您的两个示例中,您实际上修补了两个不同的东西。 Your call to patch.object patches the class FooBar , while your monkey patch patches a specific instance of FooBar . 您对patch.object调用会修补 FooBar ,而您的猴子补丁会修补FooBar的特定实例

Restoring the original object isn't important if the object will be created from scratch each time. 如果每次都从头开始创建对象,则恢复原始对象并不重要。 (You don't show it, but I assume self.foobar is being created in a setUp method, so that even though you replace its _get_foo method, you aren't reusing that specific object in multiple tests.) (你没有展示它,但我假设self.foobar是在setUp方法中创建的,所以即使你替换它的_get_foo方法,你也不会在多个测试中重用那个特定的对象。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM