Test whether a function is called inside another function in unit testing - python

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 ?

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().

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')

Related

Is it possible to unit test the parameters that I pass to the function in python?

In this scenario:
In FileA:
from FileB import BJob
class EasyJob
def __init__():
self.job = BJob()
def launch_job_in_A():
self.job.launch_job_in_B(cpu=100, memory=200)
In FileB:
class BJob():
def __init__():
pass
def launch_job_in_B(cpu=0, memory=0):
do_some_thing(cpu, memory)
...
Is there a way to write a unit test for launch_job_in_A() function and also verify whether we do pass cpu=100 and memory=200 to launch_job_in_B() function successfully?
Broadly question is like, is it possible to check the parameter we passed to the function?
You can create a Mock via unittest.mock.patch and then use the assert_called_once_with method to verify the function call:
import unittest
from unittest import TestCase
from unittest.mock import patch
from FileA import EasyJob
class TestEasyJob(TestCase):
def test_launch_job_in_A(self):
with patch('FileB.BJob.launch_job_in_B') as mock:
job = EasyJob()
job.launch_job_in_A()
mock.assert_called_once_with(cpu=100, memory=200)
unittest.main()
Yes, you would replace self.job with a mock object and its launch_job_in_B with a mock method.
This would be easier if there was an option to pass in the BJob, rather than hard coding it. This avoids having to mock every call to launch_job_in_B which might have unexpected side effects. This also makes the class more flexible.
from FileB import BJob
class EasyJob
def __init__(bjob=BJob()):
self.job = bjob
def launch_job_in_A():
self.job.launch_job_in_B(cpu=100, memory=200)
Now we can mock the method just for a single object.
from FileA import EasyJob
from FileB import BJob
from unittest.mock import MagicMock
# Set up the mocked object and method.
mock_bjob = BJob()
# If it needs to return something, configure that.
mock_bjob.launch_job_in_B() = MagicMock()
# Make the EasyJob with the mocked BJob
ejob = EasyJob(bjob=mock_bjob)
# Call the method in question.
ejob.launch_job_in_A()
# Check if the method was called with the correct arguments.
mock_bjob.method.assert_called_once_with(cpu=100, memory=200)
BJob.launch_job_in_B would be tested in its own unit test.

Test instance of class that mocked method is called from in Python

I am mocking out a method of a class and want to test the instance of the class that the method was called from to test that the creation part of my function works as expected.
In my particular case do_stuff tries to write bar_instance to an Excel File and I don't want that to happen i.e.
def create_instance(*args):
return Bar(*args)
class Bar():
def __init__(self, *args):
self.args = args
def do_stuff(self):
pass
def foo(*args):
bar_instance = create_instance(*args)
bar_instance.do_stuff()
Then in a testing file
from unittest import TestCase
from unittest.mock import patch
from path.to.file import foo
class TestFoo(TestCase):
#patch('path.to.file.Bar.do_stuff')
def test_foo(self, mock_do_stuff):
test_args = [1]
_ = foo(*test_args)
# Test here the instance of `Bar` that `mock_do_stuff` was called from
# Something like
actual_args = list(bar_instance.args)
self.assertEqual(test_args, actual_args)
I put a break in the test function after foo(*test_args) is run but can't see any way from the mocked method of accessing the instance of Bar it was called from and am a bit stuck. I don't want to mock out Bar further up the code as I want to make sure the correct instance of Bar is being created.
In your code example, there are three things that might need testing: function create_instance, class Bar and function foo. I understand your test code such that you want to ensure that function foo calls do_stuff on the instance returned by create_instance.
Since the original create_instance function has control over the created instance, a solution of your problem is to mock create_instance such that your test gains control of the object that is handed over to foo:
import unittest
from unittest import TestCase
from unittest.mock import patch, MagicMock
from SO_60624698 import foo
class TestFoo(TestCase):
#patch('SO_60624698.create_instance')
def test_foo_calls_do_stuff_on_proper_instance (
self, create_instance_mock ):
# Setup
Bar_mock = MagicMock()
create_instance_mock.return_value = Bar_mock
# Exercise
foo(1, 2, 3) # args are irrelevant
# Verify
Bar_mock.do_stuff.assert_called()
if __name__ == '__main__':
unittest.main()
In addition, you might also want to test if foo passes the arguments correctly to create_instance. This could be implemented as a separate test:
...
#patch('SO_60624698.create_instance')
def test_foo_passes_arguments_to_create_instance (
self, create_instance_mock ):
# Setup
create_instance_mock.return_value = MagicMock()
# Exercise
foo(1, 22, 333)
# Verify
create_instance_mock.assert_called_with(1, 22, 333)
And, certainly, to complete the whole test of the object generation, you could test create_instance directly, by calling it and checking on the returned instance of Bar if it has used its arguments correctly for the construction of the Bar instance.
As patch returns an instance of Mock (or actually MagicMock, but it inherits the relevant methods from its base - Mock), you have the assert_called_with method available, which should do the trick.
Note that this method is sensitive to args/kwargs - you have to assert the exact same call.
Another note: it might be a better practice to use patch.object instead of patch here

(pytest) Why doesn't property mock work in fixture?

I have a class with some properties. In my test, I need to set up a fixture, and have the properties mocked. However, the patch only works in the fixture function, not when the fixture is called. Any idea how to fix this?
Here is the simplified version of the problem. Let's assume that this is my class Panda:
class Panda(object):
def __init__(self, name):
self.panda_name = name
#property
def name(self):
return self.panda_name
and this is my test
import pytest
from unittest.mock import patch, PropertyMock
from tmp import Panda
#pytest.fixture
#patch(
'tmp.Panda.name',
new_callable=PropertyMock,
return_value="yuanyuan")
def fixture_panda(mk_name):
p = Panda("this name should not matter")
print(p.name) # print "yuanyuan"
return p
def test_panda_fixture(fixture_panda):
p = fixture_panda
print(p.name) # print "this name should not matter"
# this test fails
assert p.name == "yuanyuan"
The first print function in fixture_panda would print yuanyuan, which means the propertyMock works as expected. However the 2nd print function in test_panda_fixture print this name should not matter, which means the propertyMock doesn't work here. Any idea why this happens and how to fix this?
If you want to monkeypatch something in pytest, you can use their built-in fixture monkeypatch, which can be inserted into all fixtures with scope = function. Here is an example from my codebase:
#pytest.fixture(scope="function", autouse=True)
def no_jwt(monkeypatch):
"""Monkeypatch the JWT verification functions for tests"""
monkeypatch.setattr("flask_jwt_extended.verify_jwt_in_request", lambda: print("Verify"))
If I apply it to your example, I think something like this should work:
#pytest.fixture
def fixture_panda(monkeypatch, mk_name):
monkeypatch.setattr('tmp.Panda.name', "yuanyuan")
p = Panda("this name should not matter")
print(p.name) # print "yuanyuan"
return p
You have three problems. Firstly, you're patching the fixture function but you should be patching the test function. This is because the way you've written it, the assertion falls outside the scope of the patching.
Secondly you should ditch the superfluous mkname.
Thirdly, your return_value is in the wrong place; it needs to apply to the PropertyMock object which the patch returns, not as a parameter to the patching function. When using new_callable you need to set it within the test setup, e.g.:
#patch('tmp.Panda.name', new_callable=PropertyMock)
def test_panda_fixture(mock_name, fixture_panda):
mock_name.return_value = "yuanyuan"
...
However you can do it within the decorator by using new instead of new_callable. Here's a working version which shows that approach:
import pytest
from unittest.mock import patch, PropertyMock
from tmp import Panda
#pytest.fixture
def fixture_panda():
p = Panda("this name should not matter")
print(p.name) # print "yuanyuan"
return p
#patch('tmp.Panda.name', new=PropertyMock(return_value="yuanyuan"))
def test_panda_fixture(fixture_panda):
p = fixture_panda
print(p.name) # print "this name should not matter"
# this test fails
assert p.name == "yuanyuan"

Python magic method for variable being accessed?

I am looking for a magic method similar to the __get__ method, but in my case the variable is not inside another class, I want something like:
class A(object):
def __similar_to_get__(self):
print 'called'
return self
a = A()
b = a
>>> 'called'
Is it possible?
The reason I am asking this is, I am using a python mock library, let's say a function I am testing uses URI attribute, and I want to mock it to return different values in subsequent calls. Eg:
class WebService(obj):
URI = 'http://works.com'
def dowork(self):
call_api(self.URI)
For me to mock a failure I am using the mock library:
mock = MagicMock()
mock.side_effect = ['http://fail.com', 'http://works.com']
with patch('WebService.URI', mock):
# do the testing
But the problem is I can only get mock to return the urls by calling the callable mock() not just simply accessing mock
PS: I am a mock noob.
Not directly answering my own question, I managed to use a property to work around this:
from dps.px.pxpost import PxPost
mock = MagicMock()
mock.side_effect = ['http://doesnotexist', PxPost.URI]
def URI(self):
return mock()
with patch('django.conf.settings.CELERY_ALWAYS_EAGER', True, create=True):
with patch('dps.px.pxpost.PxPost.URI', property(URI)):
self.transaction.process()
for sub_transaction in self.transaction.sub_transactions.all():
self.assertTrue(isinstance(sub_transaction.state, CompletedSubTransaction))
self.assertTrue(sub_transaction.transaction_logs.count() > 0)
self.assertTrue(isinstance(self.transaction.state, CompletedTransaction))

Mocking a class: Mock() or patch()?

I am using mock with Python and was wondering which of those two approaches is better (read: more pythonic).
Method one: Just create a mock object and use that. The code looks like:
def test_one (self):
mock = Mock()
mock.method.return_value = True
self.sut.something(mock) # This should called mock.method and checks the result.
self.assertTrue(mock.method.called)
Method two: Use patch to create a mock. The code looks like:
#patch("MyClass")
def test_two (self, mock):
instance = mock.return_value
instance.method.return_value = True
self.sut.something(instance) # This should called mock.method and checks the result.
self.assertTrue(instance.method.called)
Both methods do the same thing. I am unsure of the differences.
Could anyone enlighten me?
mock.patch is a very very different critter than mock.Mock. patch replaces the class with a mock object and lets you work with the mock instance. Take a look at this snippet:
>>> class MyClass(object):
... def __init__(self):
... print 'Created MyClass#{0}'.format(id(self))
...
>>> def create_instance():
... return MyClass()
...
>>> x = create_instance()
Created MyClass#4299548304
>>>
>>> #mock.patch('__main__.MyClass')
... def create_instance2(MyClass):
... MyClass.return_value = 'foo'
... return create_instance()
...
>>> i = create_instance2()
>>> i
'foo'
>>> def create_instance():
... print MyClass
... return MyClass()
...
>>> create_instance2()
<mock.Mock object at 0x100505d90>
'foo'
>>> create_instance()
<class '__main__.MyClass'>
Created MyClass#4300234128
<__main__.MyClass object at 0x100505d90>
patch replaces MyClass in a way that allows you to control the usage of the class in functions that you call. Once you patch a class, references to the class are completely replaced by the mock instance.
mock.patch is usually used when you are testing something that creates a new instance of a class inside of the test. mock.Mock instances are clearer and are preferred. If your self.sut.something method created an instance of MyClass instead of receiving an instance as a parameter, then mock.patch would be appropriate here.
I've got a YouTube video on this.
Short answer: Use mock when you're passing in the thing that you want mocked, and patch if you're not. Of the two, mock is strongly preferred because it means you're writing code with proper dependency injection.
Silly example:
# Use a mock to test this.
my_custom_tweeter(twitter_api, sentence):
sentence.replace('cks','x') # We're cool and hip.
twitter_api.send(sentence)
# Use a patch to mock out twitter_api. You have to patch the Twitter() module/class
# and have it return a mock. Much uglier, but sometimes necessary.
my_badly_written_tweeter(sentence):
twitter_api = Twitter(user="XXX", password="YYY")
sentence.replace('cks','x')
twitter_api.send(sentence)
Key points which explain difference and provide guidance upon working with unittest.mock
Use Mock if you want to replace some interface elements(passing args) of the object under test
Use patch if you want to replace internal call to some objects and imported modules of the object under test
Always provide spec from the object you are mocking
With patch you can always provide autospec
With Mock you can provide spec
Instead of Mock, you can use create_autospec, which intended to create Mock objects with specification.
In the question above the right answer would be to use Mock, or to be more precise create_autospec (because it will add spec to the mock methods of the class you are mocking), the defined spec on the mock will be helpful in case of an attempt to call method of the class which doesn't exists ( regardless signature), please see some
from unittest import TestCase
from unittest.mock import Mock, create_autospec, patch
class MyClass:
#staticmethod
def method(foo, bar):
print(foo)
def something(some_class: MyClass):
arg = 1
# Would fail becuase of wrong parameters passed to methd.
return some_class.method(arg)
def second(some_class: MyClass):
arg = 1
return some_class.unexisted_method(arg)
class TestSomethingTestCase(TestCase):
def test_something_with_autospec(self):
mock = create_autospec(MyClass)
mock.method.return_value = True
# Fails because of signature misuse.
result = something(mock)
self.assertTrue(result)
self.assertTrue(mock.method.called)
def test_something(self):
mock = Mock() # Note that Mock(spec=MyClass) will also pass, because signatures of mock don't have spec.
mock.method.return_value = True
result = something(mock)
self.assertTrue(result)
self.assertTrue(mock.method.called)
def test_second_with_patch_autospec(self):
with patch(f'{__name__}.MyClass', autospec=True) as mock:
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
class TestSecondTestCase(TestCase):
def test_second_with_autospec(self):
mock = Mock(spec=MyClass)
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
def test_second_with_patch_autospec(self):
with patch(f'{__name__}.MyClass', autospec=True) as mock:
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
def test_second(self):
mock = Mock()
mock.unexisted_method.return_value = True
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
The test cases with defined spec used fail because methods called from something and second functions aren't complaint with MyClass, which means - they catch bugs, whereas default Mock will display.
As a side note there is one more option: use patch.object to mock just the class method which is called with.
The good use cases for patch would be the case when the class is used as inner part of function:
def something():
arg = 1
return MyClass.method(arg)
Then you will want to use patch as a decorator to mock the MyClass.

Categories

Resources