在Python中使用’@ patch.object’和’with patch.object’有什么区别?

在为我的应用程序编写单元测试时,我一直在使用@ mock.patch和@ patch.object装饰器.但是现在,对于我使用装饰器的一些单元测试,我收到一个错误’TypeError:staticmethod object is not iterator’.

但是使用相同的代码,如果我使用mock.patch.object或mock.patch.object,一切正常.

例如,在我的测试类中,我有这个方法:

@staticmethod
def my_mock():
   ...do something

当我尝试以下单元测试时

@mock.patch('mypackage.mymodule.my_method', side_effect=my_mock)
def test_something(self, my_method_mocked):
    ...test something

我收到’TypeError:staticmethod object is not iterator’之前声明的错误消息.

但是,当我尝试这种方式

def test_something(self):
    with patch.object(mymodule, "my_method") as mocked_method:
        mocked_method.side_effect = self.my_mock
        ...test something

一切都很完美.

我已经阅读了有关模拟和单元测试的Python文档,但我找不到任何有关此行为的解释.

使用装饰器模式和with模式有什么区别?哪里可以找到更多相关信息?

为了更清楚,这是我的代码结构:

class TestClass(unittest.TestCase):

    @staticmethod
    def my_mock():
    ...mock
        return service

    # doesn't work
    @mock.patch('mypackage.mymodule.my_method', side_effect=my_mock)
    def test_something(self, my_method_mocked):
        ...test something

    # work 
    def test_something(self):
    with patch.object(mymodule, "my_method") as mocked_method:
        mocked_method.side_effect = self.my_mock
        ...test something

这就是为什么我不能做TestClass.my_mock.如果我这样做,我会收到参考错误.

最佳答案 您正在看到Python的描述符协议的影响.区别不在于您如何调用补丁,而是在每种情况下分配给side_effect属性的值中.

class A(object):
    @staticmethod
    def my_mock():
        pass

    print type(my_mock)    # As in your decorator case

# As in your context manager case
print type(A.my_mock)
print type(A().my_mock)

如果运行此代码,您将看到类声明中的print语句输出< type’staticmethod’>,因为您有对方法本身的引用.

另外两个打印语句输出< type’function’>因为你没有对方法的引用;你有一个方法的__get__方法的返回值的引用.这两个电话相当于

print type(A.__dict__['my_mock'].__get__(A))
print type(A.__dict__['my_mock'].__get__(A()))

有关如何使用描述符实现三种类型的方法(静态,类和实例)的更全面讨论,请参见https://docs.python.org/2/howto/descriptor.html.

实际的错误是因为patch期望一个callable作为side_effect参数的值,如果失败,它需要一个可迭代的返回值. staticmethod对象既不可调用也不可迭代.
(试一试:A .__ dict __ [‘my_mock’]().)

为确保获得该功能,您需要通过该类访问该方法.

class Foo(object):
    @staticmethod
    def my_mock():
        "whatever it does"

@mock.patch('mypackage.mymodule.my_method', side_effect=Foo.my_mock)
def test_something(self, my_method_mocked):
    ...test something
点赞