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

标签 python python-2.7 unit-testing python-unittest python-mock

在为我的应用程序编写单元测试时,我一直使用 @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 文档,但我找不到对这种行为的任何解释。

使用装饰器模式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 的描述符协议(protocol)的效果。区别不在于您如何调用 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期望一个可调用对象作为 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

关于python - 在 Python 中使用 '@patch.object' 和 'with patch.object' 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38882187/

相关文章:

java - 使用 JUnit 进行数据库单元测试

c# - 下载文件对话框的 Csharp 单元测试

python - Python中t检验的置信区间(均值之间的差异)

python - 以 ; 结尾的 Python 语句有什么区别?

python - 如何用 selenium 测试 jquery ajax 标签?

python - 在 python 中从文件中读取 C 结构

python - 用python编码元组列表?

python - requests.request ('POST' 和 request.post 之间的区别

python - 如何将Tensorflow张量尺寸(形状)作为int值?

python - 将行与之前的所有行进行比较