The first two functions display_pane_1 and template_1 are easily tested
in the method test_1. I want to refactor these two functions into a single function display_pane_2.
lambdademo.py:
def display_pane_1():
display_register(template_1)
def template_1():
return 'hello mum'
def display_pane_2():
display_register(lambda: 'hello mum')
def display_register(template):
print(template())
test_lambdademo.py
import unittest
import unittest.mock as mock
import lambdademo
class TestLambda1(unittest.TestCase):
def setUp(self):
p = mock.patch('lambdademo.display_register')
self.mock_display_register = p.start()
self.addCleanup(p.stop)
def test_1(self):
lambdademo.display_pane_1()
self.mock_display_register.assert_called_with(lambdademo.template_1)
def test_2(self):
lambdademo.display_pane_2()
self.mock_display_register.assert_called_with('????????')
Can you help me write a valid test for display_pane_2? I would like to test the complete lambda expression i.e. lambda x: 'hell mum' should fail.
I've tried two paths to a solution.
The first option is a simple copy of test_1,replacing the argument of lambdademo.template_1 with a mock of lambda. I couldn't find anything in the manual that suggests how I should mock an expression like lambda.
If it is in the manual please tell me where.
My second option followed from a wider search here on Stack Overflow and out on the Internet. The lack of responsive hits for 'python expression unittest',
'python lambda unittest', 'python expression mock', or 'python lambda mock'
suggested that I may be asking the wrong question. Is my assumption that I will need to mock the lambda expression wrong?
I am aware that a simple coding solution would be to keep the original code but at this point I'm more interested in filling in a gap in my knowledge.
If the lambda expression is accessible somewhere like an attribute of a class or a module, then you could mock it, but that seems very unlikely. Usually, a lambda expression is used when you don't need a reference to the function. Otherwise, you'd just use a regular function.
However, you can retrieve the arguments to all calls on a mock object, so you could look at the lambda expression that was passed in. In an example like the one you gave, the simplest thing to do would just be to call the lambda expression and see what it returns.
from mock import patch
def foo(bar):
return bar()
def baz():
return 42
print foo(baz)
with patch('__main__.foo') as mock_foo:
print foo(baz)
print foo(lambda: 'six by nine')
assert mock_foo.call_args_list[0][0][0]() == 42
assert mock_foo.call_args_list[1][0][0]() == 'six by nine'
If for some reason you don't want to do that, then you could use the inspect module to look at the lambda expression. Here's an example that just dumps the source code lines where the function was defined:
from inspect import getsource
from mock import patch
def foo(bar):
return bar()
def baz():
return 42
print foo(baz)
with patch('__main__.foo') as mock_foo:
print foo(baz)
print foo(lambda: 'six by nine')
print mock_foo.call_args_list
for call_args in mock_foo.call_args_list:
print '---'
print getsource(call_args[0][0])
The results:
42
<MagicMock name='foo()' id='140595519812048'>
<MagicMock name='foo()' id='140595519812048'>
[call(<function baz at 0x7fdef208fc08>),
call(<function <lambda> at 0x7fdef208fe60>)]
---
def baz():
return 42
---
print foo(lambda: 'six by nine')
Here is a version of your test that passes with your example code. It tests both ways: calling the template and inspecting the source of the template.
# test_lambdademo.py
from inspect import getsource
import unittest
import unittest.mock as mock
import lambdademo
class TestLambda1(unittest.TestCase):
def setUp(self):
p = mock.patch('lambdademo.display_register')
self.mock_display_register = p.start()
self.addCleanup(p.stop)
def test_1(self):
lambdademo.display_pane_1()
self.mock_display_register.assert_called_with(lambdademo.template_1)
def test_2(self):
lambdademo.display_pane_2()
template = self.mock_display_register.call_args[0][0]
template_content = template()
template_source = getsource(template)
self.assertEqual('hello mum', template_content)
self.assertIn('hello mum', template_source)
Related
I would like to patch a class in Python in unit testing. The main code is this (mymath.py):
class MyMath:
def my_add(self, a, b):
return a + b
def add_three_and_two():
my_math = MyMath()
return my_math.my_add(3, 2)
The test class is this:
import unittest
from unittest.mock import patch
import mymath
class TestMyMath(unittest.TestCase):
#patch('mymath.MyMath')
def test_add_three_and_two(self, mymath_mock):
mymath_mock.my_add.return_value = 5
result = mymath.add_three_and_two()
mymath_mock.my_add.assert_called_once_with(3, 2)
self.assertEqual(5, result)
unittest.main()
I am getting the following error:
AssertionError: Expected 'my_add' to be called once. Called 0 times.
The last assert would also fail:
AssertionError: 5 != <MagicMock name='MyMath().my_add()' id='3006283127328'>
I would expect that the above test passes. What I did wrong?
UPDATE:
Restrictions:
I would not change the tested part if possible. (I am curious if it is even possible, and this is the point of the question.)
If not possible, then I want the least amount of change in the to be tested part. Especially I want to keep the my_add() function non-static.
Instead of patching the entire class, just patch the function.
class TestMyMath(unittest.TestCase):
#patch.object(mymath.MyMath, 'my_add')
def test_add_three_and_two(self, m):
m.return_value = 5
result = mymath.add_three_and_two()
m.assert_called_once_with(3, 2)
self.assertEqual(5, result)
I think the original problem is that my_math.my_add produces a new mock object every time it is used; you configured one Mock's return_value attribute, but then checked if another Mock instance was called. At the very least, using patch.object ensures you are disturbing your original code as little as possible.
Your code is almost there, some small changes and you'll be okay:
my_add should be a class method since self does not really play a role here.
If my_add is an instance method, then it will be harder to trace the calls, since your test will track the instance signature, not the class sig
Since you are are patching, not stubbing, you should use the "real thing", except when mocking the return value.
Here's what that looks like in your code:
class MyMath:
#classmethod
def my_add(cls, a, b):
return a + b
def add_three_and_two():
return MyMath.my_add(3, 2)
Now, the test:
import unittest
from unittest.mock import patch, MagicMock
import mymath
class TestMyMath(unittest.TestCase):
#patch('mymath.MyMath')
def test_add_three_and_two(self, mymath_mock):
# Mock what `mymath` would return
mymath_mock.my_add.return_value = 5
# We are patching, not stubbing, so use the real thing
result = mymath.add_three_and_two()
mymath.MyMath.my_add.assert_called_once_with(3, 2)
self.assertEqual(5, result)
unittest.main()
This should now work.
I have two files:- file1.py and file2.py
file2.py has following code:-
import json
def fun1():
s = "{'function1': 'val1'}"
s = json.dumps(s)
print("in fun1 ", s)
return s
def fun2():
s = "{'function2': 'value2'}"
s = json.dumps(s)
print("in fun2 ", s)
return s
def fun5():
fun2()
return fun1()
file1.py has following code
from mockito import when, unstub
from file2 import fun5
def mock_the_function():
when("file2.fun1.json").dumps(...).thenReturn("something something")
print(fun5())
unstub()
I want to mock "dumps" inside "fun1" only, not "fun2". Code which I have written is showing error. I don't want to do it by parameter comparison. Is there any other way I can have a function being passed inside "when"?
First a quick note:
json.dumps takes an object, not a string, so it's kind of redundant to to call it as you are inside fun1 and fun2. Perhaps you're looking for json.loads?
Next I'd consider some different approaches:
When you mock json.dumps, you want to mock the the json property of the file2 module, so it would just be when("file2.json")... in the setup code for your test.
Because (as above), we're mocking the json module globally in the file2 module, it's not possible to, as you asked, in that context of a single test, mock json.dumps inside of fun1 but not fun2, but what I'd suggest is to simply have two tests, and unstub in a tear down method. For example:
from unittest import TestCase
class TestExample(TestCase):
def tearDown(self):
unstub()
def test_fun1(self):
when("file2.json").dumps(...).thenReturn("something something")
# in this invocation json is stubbed
self.assertEqual(fun1(), "something something")
def test_fun2(self):
# but now unstub has been called so it won't be stubbed anymore.
self.assertEqual(fun2(), "...output of fun2...")
Another alternative is for fun1 and fun2 to take a function that will do the work that the global json module is currently doing. This use of the Dependency Inversion Principle makes the code more testable, and means you don't even need mockito in your tests. For example:
def fun1(json_decoder):
s = "..."
return json_decoder(s)
# ....
from unittest.mock import MagicMock
def test_fun_1():
mock_decoder = MagicMock()
mock_decoder.return_value = "asdf"
assert fun1(mock_decoder) == "asdf"
So I've this code that mocks two times, the first time by mocking imports with:
sys.modules['random'] = MagicMock()
The second time happens inside the unittest of a function that used that import, for example a function that used random
The tests. py is:
import sys
import unittest
from unittest import mock
from unittest.mock import MagicMock
import foo
sys.modules['random'] = MagicMock()
class test_foo(unittest.TestCase):
def test_method(self):
with mock.patch('random.choice', return_value = 2):
object = foo.FooClass(3)
self.assertEqual(2, object.method(), 'Should be 2')
def test_staticmethod(self):
with mock.patch('random.choice', return_value = 2):
object = foo.FooClass(3)
self.assertEqual(2, object.method(), 'should be 2')
The original file Foo.py is:
import random
class FooClass:
def __init__(self,arg):
self.arg = arg
def method(self):
print(random.choice)
return random.choice([1,2,3])
#staticmethod
def staticmethod():
print(random.choice)
random.choice([1,2,3])
The two mocks contrarrest each other, and the mocking of random doesn't happen.
When it prints random it actually prints:
<<bound method Random.choice of <random.Random object at 0x7fe688028018>>
I want that to print a MagicMock.
Can someone help me understand what's happening? Why are they contrarresting each other?
You don't need to update the module source with sys.modules['random'] = MagicMock() without this line it works fine <MagicMock name='choice' id='...'>. patch already does all the work for the isolated temporary updating the method. See more explanation in the docs - Where to patch
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"
e.g.
class Foobar:
def func():
print('This should never be printed.')
def func2():
print('Hello!')
def test_mock_first_func():
foobar = Foobar()
# !!! do something here to mock out foobar.func()
foobar.func()
foobar.func2()
I expect the console to output:
Hello!
Okay, apparently the documentation just goes around in roundabouts but in fact this page contains the solution:
http://www.voidspace.org.uk/python/mock/examples.html#mocking-unbound-methods
To supplement the weak documentation (high on words, low on content... such a shame) that uses confusing variable / function names in the the example, the correct way to mock the method is so:
class Foobar:
def func():
print('This should never be printed.')
def func2():
print('Hello!')
def test_mock_first_func():
with patch.object(Foobar, 'func', autospec=True) as mocked_function:
foobar = Foobar()
foobar.func() # This function will do nothing; we haven't set any expectations for mocked_function!
foobar.func2()