Here's a generalized example of the code I'm trying to test using mock. I get an AttributeError.
Here's __init__.py:
import logging
log = logging.getLogger(__name__)
class SomeError(Exception):
pass
class Stuff(object):
# stub
def method_a(self):
try:
stuff = self.method_b()
except SomeError, e:
log.error(e)
# show a user friendly error message
return 'no ponies'
return 'omg ponies'
def method_b(self):
# can raise SomeError
return ''
In tests.py I have something like this:
import mock
import unittest
from package.errors import SomeError
from mypackage import Stuff
some_error_mock = mock.Mock()
some_error_mock.side_effect = SomeError
class MyTest(unittest.TestCase):
@mock.patch.object('Stuff', 'method_b', some_error_mock)
def test_some_error(self):
# assert that method_a handles SomeError correctly
mystuff = Stuff()
a = mystuff.method_a()
self.assertTrue(a == 'no ponies')
When running the test, mock raises AttributeError saying: "Stuff does not have the attribute 'method_b'"
What am I doing wrong here?
Raising exceptions with mocks A useful attribute is side_effect . If you set this to an exception class or instance then the exception will be raised when the mock is called. >>> mock = Mock(side_effect=Exception('Boom!
mock provides a powerful mechanism for mocking objects, called patch() , which looks up an object in a given module and replaces that object with a Mock . Usually, you use patch() as a decorator or a context manager to provide a scope in which you will mock the target object.
Mock vs. MagicMock is a subclass of Mock . It contains all magic methods pre-created and ready to use (e.g. __str__ , __len__ , etc.). Therefore, you should use MagicMock when you need magic methods, and Mock if you don't need them.
Accessing the same attribute will always return the same mock. Mocks record how you use them, allowing you to make assertions about what your code has done to them. MagicMock is a subclass of Mock with all the magic methods pre-created and ready to use.
The decorator first argument should be the class of the object, you mistakenly used a string of the name of the class
@mock.patch.object('Stuff', 'method_b', some_error_mock)
should become
@mock.patch.object(Stuff, 'method_b', some_error_mock)
http://docs.python.org/dev/library/unittest.mock#patch-object
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With