首页 文章

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

提问于
浏览
4

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

但是使用相同的代码,如果我使用 mock.patch.objectmock.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 an iterator '之前声明的错误消息 .

但是,当我尝试这种方式

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

一切都很完美 .

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

使用 decorator patternwith 模式有什么区别?哪里可以找到更多相关信息?

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

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

那's why I can' t做 TestClass.my_mock . 如果我这样做,我会收到参考错误 .

2 回答

  • 1

    我想你只需要添加类名

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

    您正在看到Python的描述符协议的影响 . 区别不在于您如何调用 patch ,而是在每种情况下分配给 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'> ,因为您有对方法本身的引用 .

    另外两个 print 语句输出 <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
    

相关问题