In writing unit tests for my application, I have always been using the @mock.patch
and @patch.object
decorators. But now, for some unit tests when I use the decorator, I receive an error ' TypeError: staticmethod object is not an iterator '.
But with the same code, if I use mock.patch.object
or mock.patch.object
, everything works just fine.
For example, in my test class I have this method:
@staticmethod
def my_mock():
...do something
When I try the following unit test
@mock.patch('mypackage.mymodule.my_method', side_effect=my_mock)
def test_something(self, my_method_mocked):
...test something
I receive the error message stated before ' TypeError: staticmethod object is not an iterator '.
But when I try this way
def test_something(self):
with patch.object(mymodule, "my_method") as mocked_method:
mocked_method.side_effect = self.my_mock
...test something
then everything works perfectly.
I've read the Python documentation about mock and unit tests, but I couldn't find any explanation for this behavior.
What is the difference between using the decorator pattern and the with pattern? Where I can find more about this?
Just to be more clear, this my code structure:
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
That's why I can't do TestClass.my_mock
. If I do, I get a reference error.
You are seeing the effect of Python's descriptor protocol. The difference is not in how you are calling patch
, but in the value you are assigning to the side_effect
attribute in each case.
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)
If you run this code, you'll see that the print
statement inside the class declaration outputs <type 'staticmethod'>
, because you have a reference to the method itself.
The other two print
statements output <type 'function'>
because you don't have a reference to the method; you have a reference to the return value of the method's __get__
method. The two calls are equivalent to
print type(A.__dict__['my_mock'].__get__(A))
print type(A.__dict__['my_mock'].__get__(A()))
See https://docs.python.org/2/howto/descriptor.html for a fuller discussion of how descriptors are used to implement the three types of methods (static, class, and instance).
The actual error comes about because patch
expects a callable as the value of the side_effect
argument, and failing that, it needs an iterable of return values. A staticmethod
object is neither callable nor iterable. (Try it: A.__dict__['my_mock']()
.)
To ensure you get the function, you need to access the method through the 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
I think you just need to add the class name
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.