Reputation: 713
New to mock and patch in python. I have a class which has a method update
class myclass(object):
def update(self, name, passwd):
self.update_in(name,passwd)
def update_in(self, name, passwd):
self.name = name
self.passwd = passwd
Now in another class I have to test the update method and ascertain that the update method calls in update_in method. How do I achieve this ?
Upvotes: 3
Views: 6433
Reputation: 23711
By patch
from unittest.mock
module you can patch methods, functions, object or attribute of your production code. Now I assume myclass
in mymodule
and I will show you some simple way of how to do your test.
from unittest.mock import patch
from mymodule import myclass
m = myclass()
with patch("mymodule.myclass.update_in", autospec=True) as mock_update_in:
m.update('me', 'mypassword')
mock_update_in.assert_called_with('me', 'mypassword')
@patch("mymodule.myclass.update_in", autospec=True)
def my_test(mock_update_in):
m = myclass()
m.update('me', 'mypassword')
mock_update_in.assert_called_with('me', 'mypassword')
my_test()
Now instead of patch
you can use patch.object(myclass, "update_in", autospec=True)
and patch the reference of myclass
in the module of your tests. My feel is to use patch.object
just when you cannot do otherwise: you must be sure that you are patching the code that will be called by your test and not something else. For instance you have mymodule_b
the use from mymodule import myclass
and now you test a method in mymodule_b
like:
from mymodule import myclass
def get_registered(username, password):
m = myclass()
m.update(username, password)
return m
Now the reference of myclass
used by get_registered()
is not the one in your test module. Next test will fail
from mymodule import myclass
from mymodule_b import get_registered
with patch.object(myclass, "update_in", autospec=True) as mock_update_in:
m = get_registered('me', 'mypassword')
assert m is not None
mock_update_in.assert_called_with('me', 'mypassword')
Is a good practice take a look to Where to patch session before to start to ride patch
functions.
Just a note about use autospec=True
: autospec
is a real powerful option of patch
functions family, your patched object will take the signature and the attributes from the original reference and prevent some silly errors in your test. To understand the value of autospec
take a look to the next example:
m = myclass()
with patch("mymodule.myclass.update_in") as mock_update_in:
m.update('me', 'mypassword')
mock_update_in.assert_call_with('you', 'yourpassword')
The previous test pass even if you check by the wrong arguments just because mock_update_in
is a standard MagicMock()
return a MagicMock
object for every attribute you ask or every method you call without raise any exception: in that scenario mock_update_in.assert_call_with('you', 'yourpassword')
will return a MagicMock()
.
Upvotes: 3
Reputation: 599490
You should use mock.patch
to replace the method with a mock, and then you can assert various things about the mock after calling your update
method.
patcher = mock.patch.object(myclass, 'update_in')
patched = patcher.start()
m=myclass()
m.update('foo', 'bar')
assert patched.call_count == 1
patched.assert_called_with('foo', 'bar')
Upvotes: 1