在 Python 中使用 '@patch.object' 和 'with patch.object' 有什么区别?
What is the difference between using the '@patch.object' and 'with patch.object' in Python?
在为我的应用程序编写单元测试时,我一直使用 @mock.patch
和 @patch.object
装饰器。但是现在,对于某些使用装饰器的单元测试,我收到错误“TypeError: staticmethod object is not an iterator”。
但是使用相同的代码,如果我使用 mock.patch.object
或 mock.patch.object
,一切正常。
比如在我的测试中class我有这个方法:
@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
。如果这样做,我会收到参考错误。
我想你只需要添加 class 名称
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
您正在看到 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)
如果你 运行 这段代码,你会看到 class 声明中的 print
语句输出 <type 'staticmethod'>
,因为你有一个对该方法的引用本身。
其他两个 print
语句输出 <type 'function'>
因为你 没有 引用该方法;您引用了该方法的 __get__
方法的 return 值。两次调用相当于
print type(A.__dict__['my_mock'].__get__(A))
print type(A.__dict__['my_mock'].__get__(A()))
有关如何使用描述符来实现三种类型的方法(静态、class 和实例)的更全面讨论,请参阅 https://docs.python.org/2/howto/descriptor.html。
实际错误的发生是因为 patch
期望一个可调用对象作为 side_effect
参数的值,如果失败,它需要一个 return 值的可迭代对象。 staticmethod
对象既不可调用也不可迭代。
(试一试:A.__dict__['my_mock']()
。)
为确保您获得该功能,您需要通过class访问该方法。
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
在为我的应用程序编写单元测试时,我一直使用 @mock.patch
和 @patch.object
装饰器。但是现在,对于某些使用装饰器的单元测试,我收到错误“TypeError: staticmethod object is not an iterator”。
但是使用相同的代码,如果我使用 mock.patch.object
或 mock.patch.object
,一切正常。
比如在我的测试中class我有这个方法:
@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
。如果这样做,我会收到参考错误。
我想你只需要添加 class 名称
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
您正在看到 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)
如果你 运行 这段代码,你会看到 class 声明中的 print
语句输出 <type 'staticmethod'>
,因为你有一个对该方法的引用本身。
其他两个 print
语句输出 <type 'function'>
因为你 没有 引用该方法;您引用了该方法的 __get__
方法的 return 值。两次调用相当于
print type(A.__dict__['my_mock'].__get__(A))
print type(A.__dict__['my_mock'].__get__(A()))
有关如何使用描述符来实现三种类型的方法(静态、class 和实例)的更全面讨论,请参阅 https://docs.python.org/2/howto/descriptor.html。
实际错误的发生是因为 patch
期望一个可调用对象作为 side_effect
参数的值,如果失败,它需要一个 return 值的可迭代对象。 staticmethod
对象既不可调用也不可迭代。
(试一试:A.__dict__['my_mock']()
。)
为确保您获得该功能,您需要通过class访问该方法。
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