I am having trouble with checking if an object is being constructed with the proper params from another instance of an object. In the below example, I am trying to create an instance of B within an instance of A. I want to check the parameter being used in the constructor of B inside of the A instance. When I run the test below, I get:
AssertionError: assert None
[CPython36:setup:stdout] E + where None = <bound method NonCallableMock.assert_called_with of <MagicMock name='B' id='139968329210736'>>(4)
[CPython36:setup:stdout] E + where <bound method NonCallableMock.assert_called_with of <MagicMock name='B' id='139968329210736'>> = <MagicMock name='B' id='139968329210736'>.assert_called_with
I am not quite sure what I am doing wrong here and have looked at other stack overflow posts, but have not been able to solve my issue.
b.py:
class B(object):
def __init__(self, x):
self.x = x
def square(self):
return x * x
a.py:
from b import B
class A(object):
def foo(self):
b = B(4)
b.square()
test_a.py:
import unittest
from unittest.mock import patch
from a import A
class TestA(unittest.TestCase):
#patch('a.B')
def test_foo(self, mock_b):
self.a = A()
self.a.foo()
assert mock_b.assert_called_with(4)
The method assert_called_with returns None, so what your are doing is like doing
assert None
And that's basically the error message you are getting.
You can just use
mock_b.assert_called_with(4)
Which has an assert internally and pytest will display it correctly in case of failure. Try to check it by changing the argument value.
Alternatively, if you prefer to write the assert yourself, you can do something like this:
from unittest.mock import call
assert mock_b.call_args_list == [call(4)]
Or just the last call:
from unittest.mock import call
assert mock_b.call_args == call(4)
Related
Suppose I have some function A.foo() that instantiates and uses an instance of B, calling the member function bar on it.
How can I set return_value on a mocked instance of B when I'm testing my A class, given that I don't have access to the instance of B? Maybe some code would illustrate this better:
import unittest
import unittest.mock
import pandas
class A:
def foo(self):
b = B()
return b.bar()
class B:
def bar():
return 1
#unittest.mock.patch("__main__.B")
class MyTestCase(unittest.TestCase):
def test_case_1(self, MockB):
MockB.bar.return_value = 2
a = A()
self.assertEqual(a.foo(), 2)
test_case = MyTestCase()
test_case.test_case_1()
This fails with;
AssertionError: <MagicMock name='B().bar()' id='140542513129176'> != 2
Apparently the line MockB.bar.return_value = 2 didn't modify the return value of the method.
I think you are not initiating the MockB. You can directly mock "main.B.bar":
#unittest.mock.patch("__main__.B.bar")
class MyTestCase(unittest.TestCase):
def test_case_1(self, MockB):
MockB.return_value = 2
a = A()
self.assertEqual(a.foo(), 2)
You have just 1 mistake in your code. Replace this line:
MockB.bar.return_value = 2
To:
MockB.return_value.bar.return_value = 2
And it would work.
I assume the piece of code you pasted is just a toy example. If the class A and B lies on another file e.g. src/somedir/somefile.py, don't forget to patch the full path.
#unittest.mock.patch("src.somedir.somefile.B")
class MyTestCase(unittest.TestCase):
...
Update
To further expand on this, you can see some usage in the docs:
>>> class Class:
... def method(self):
... pass
...
>>> with patch('__main__.Class') as MockClass:
... instance = MockClass.return_value
... instance.method.return_value = 'foo'
... assert Class() is instance
... assert Class().method() == 'foo'
...
So in your case:
MockB.bar.return_value is like calling a static method e.g. print(MockB.bar())
MockB.return_value.bar.return_value is like calling a class/instance method e.g. print(MockB().bar())
To visualize this:
import unittest.mock
class SomeClass:
def method(self):
return 1
#unittest.mock.patch("__main__.SomeClass")
def test_mock(mock_class):
print(mock_class)
print(mock_class.return_value)
mock_class.method.return_value = -10
mock_class.return_value.method.return_value = -20
print(SomeClass.method())
print(SomeClass().method())
test_mock()
$ python3 test_src.py
<MagicMock name='SomeClass' id='140568144584128'>
<MagicMock name='SomeClass()' id='140568144785952'>
-10
-20
As you can see, mock_class.return_value is the one used for instance operations such as SomeClass().method().
You can solve this without mock.patch. Change the foo method to accept a factory for the dependency it should construct (DI).
class A:
def foo(self, b_factory: 'Callable[[], B]' = B):
b = b_factory()
return b.bar()
def normal_code():
a = A()
assert a.foo() == ...
def test():
dummy_b = ... # build a dummy object here however you like
a = A()
assert a.foo(b_factory=lambda: dummy_b) == 2
Let's suppose I have a big class with methods that make many references to self. For example:
from unittest import mock
import json
import Gamma
class Alpha:
def __init__(self):
self.a = json.loads('file_A')
self.b = json.loads('file_B')
self.c = None
self.d = None
self.e = Gamma()
def foo(self):
json.dumps(self.d)
def bar(self, dummy):
self.c = dummy.x
self.d = dummy.y
self.foo()
class Beta:
def __init__(self):
self.x = json.loads('file_X')
self.y = json.loads('file_Y')
Let's say I want to test the bar method in the above example utilizing mock. This is what I'm trying but I'm obviously missing something here:
#mock.patch('Beta', autospec=True)
#mock.patch('Alpha', autospec=True)
def test_bar(mock_alpha, mock_beta):
# Set mock values so the Beta class gets instantiated properly
mock_beta.x = 8
mock_beta.y = 9
# Call the bar method from mocked Alpha class
mock_alpha.bar(mock_beta)
# Test whether bar method updated the Alpha class as desired
assert mock_alpha.c == 8
assert mock_alpha.foo.called
These are the errors I get for the two asserts:
> raise AttributeError("Mock object has no attribute %r" % name)
E AttributeError: Mock object has no attribute 'c'
> assert mock_alpha.foo.called
E AssertionError: assert False
E + where False = <MagicMock name='Alpha.foo' spec='function' id='5324111568'>.called
E + where <MagicMock name='Alpha.foo' spec='function' id='5324111568'> = <MagicMock name='Alpha' spec='Alpha' id='5323992784'>.foo
How do I go about testing everything that foo does using mock?
PS: This is a stripped down example; it might make more sense to mock json object here in this particular example. However, in my real use case, the Alpha class is very complicated and would be a lot of work to mock all the endpoints. My question is confined to whether there's a way to mock instance of a class the way I'm attempting (unsuccessfully) to do in the example.
I will patch json.loads() method instead of patching Beta class. Besides, I patched .foo() method of Alpha class.
E.g.
main.py:
import json
class Alpha:
def __init__(self):
self.a = json.loads('file_A')
self.b = json.loads('file_B')
self.c = None
self.d = None
def foo(self):
json.dumps(self.d)
def bar(self, dummy):
self.c = dummy.x
self.d = dummy.y
self.foo()
class Beta:
def __init__(self):
self.x = json.loads('file_X')
self.y = json.loads('file_Y')
test_main.py:
from unittest import mock
import unittest
from main import Alpha, Beta
class TestAlpha(unittest.TestCase):
#mock.patch('main.json.loads')
#mock.patch('main.Alpha.foo')
def test_bar(self, mocked_foo, mocked_json_loads):
def json_loads_side_effect(s):
if s == 'file_X':
return 'a'
if s == 'file_Y':
return 'b'
mocked_json_loads.side_effect = json_loads_side_effect
alpha = Alpha()
beta = Beta()
alpha.bar(beta)
self.assertEqual(alpha.c, 'a')
self.assertEqual(alpha.d, 'b')
mocked_foo.assert_called_once()
if __name__ == '__main__':
unittest.main()
test result:
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Name Stmts Miss Cover Missing
-----------------------------------------------------------------------
src/stackoverflow/68402729/main.py 17 1 94% 12
src/stackoverflow/68402729/test_main.py 21 0 100%
-----------------------------------------------------------------------
TOTAL 38 1 97%
After researching this for a while and considering #slideshowp2 's answer to this question. I have found a solution to be most close to what I was looking for. It seems like my initial idea of mocking entire class Alpha is unfeasible, instead I can mock any endpoints of Alpha but will need to have Alpha instantiated one way or another.
Here's my final solution that works.
#pytest.fixture
def set_up_alpha():
"""
Use this fixture to set-up an instance of Alpha object
Mock any endpoints as necessary
"""
with mock.patch.object(json, 'loads') as mock_json_loads:
mock_json_loads.side_effect = lambda x: "test_string"
a = Alpha()
yield a
#mock.patch.object(Alpha, 'foo', autospec=True)
def test_bar(mock_foo, set_up_alpha):
"""
GIVEN an Alpha object
AND a mocked Beta object
WHEN the bar method is invoked
THEN corresponding instances of Alpha object are updated
AND method foo is called
AND the method does not return anything
"""
# Use a mocked object for Beta instance
class MockBeta:
x = "test_x"
y = "test_y"
# Instantiate an Alpha object
a = set_up_alpha
output = a.bar(MockBeta)
# Test whether bar method updated the Alpha class as desired
assert a.c == "test_x"
assert a.d == "test_y"
assert mock_foo.called
assert output is None
I am noticing a weird behavior with assert_called_once and assert_called_once_with in python. This is my real simple test:
File module/a.py
from .b import B
class A(object):
def __init__(self):
self.b = B("hi")
def call_b_hello(self):
print(self.b.hello())
File module/b.py
class B(object):
def __init__(self, string):
print("created B")
self.string = string;
def hello(self):
return self.string
These are my tests:
import unittest
from mock import patch
from module.a import A
class MCVETests(unittest.TestCase):
#patch('module.a.B')
def testAcallBwithMockPassCorrect(self, b1):
a = A()
b1.assert_called_once_with("hi")
a.call_b_hello()
a.b.hello.assert_called_once()
#patch('module.a.B')
def testAcallBwithMockPassCorrectWith(self, b1):
a = A()
b1.assert_called_once_with("hi")
a.call_b_hello()
a.b.hello.assert_called_once_with()
#patch('module.a.B')
def testAcallBwithMockFailCorrectWith(self, b1):
a = A()
b1.assert_called_once_with("hi")
a.b.hello.assert_called_once_with()
#patch('module.a.B')
def testAcallBwithMockPassWrong(self, b1):
a = A()
b1.assert_called_once_with("hi")
a.b.hello.assert_called_once()
if __name__ == '__main__':
unittest.main()
My problem as stated in the name of the function is:
Test 1 passes correctly
Test 2 passes correctly
Test 3 fails correctly (I've removed the call to b)
Test 4 passes I am not sure why.
Am I doing something wrong? I am not sure but reading the documentation docs python:
assert_called_once(*args, **kwargs)
Assert that the mock was called exactly once.
This is old, but for others landing here...
For python < 3.6, assert_called_once isn't a thing and so you're actually making a mocked function call which doesn't error
Please see: http://engineroom.trackmaven.com/blog/mocking-mistakes/
You can check the call count instead.
I am interested in patching a method which is called by another method in one file. Example - original.py file contains -
def A():
a = 10
b = 5
return a*b;
def B():
c = A()
return c* 10
I want to write unit test for this file , say call it test.py
import mock
import unittest
class TestOriginal(unitest.TestCase):
def test_Original_method(self):
with patch(''):
How can I use patch and mock modules to test original.py. I want A() to always return MagicMock() object instead of an integer.
You simply patch out the A global in the module under test. I'd use the #patch decorator syntax here:
import mock
import unittest
import module_under_test
class TestOriginal(unitest.TestCase):
#patch('module_under_test.A')
def test_Original_method(self, mocked_A):
mocked_A.return_value = 42
result = module_under_test.B()
mocked_A.assert_called_with()
self.assertEqual(result, 420)
This passes in the MagicMock mock object for A() as an extra argument to the test method.
Note that we explicitly named the module here. You could also use patch.object(), just naming the attribute on the module (which are your module globals):
class TestOriginal(unitest.TestCase):
#patch.object(module_under_test, 'A')
def test_Original_method(self, mocked_A):
mocked_A.return_value = 42
result = module_under_test.B()
mocked_A.assert_called_with()
self.assertEqual(result, 420)
You can still use a with statement too, of course:
class TestOriginal(unitest.TestCase):
def test_Original_method(self):
with patch('module_under_test.A') as mocked_A:
mocked_A.return_value = 42
result = module_under_test.B()
mocked_A.assert_called_with()
self.assertEqual(result, 420)
I am trying to mock an import during testing
Test.py looks like
# Store original __import__
orig_import = __import__
b_mock = mock.Mock()
def import_mock(name, *args):
if name == 'B':
return b_mock
return orig_import(name, *args)
with mock.patch('__builtin__.__import__', side_effect=import_mock):
import A
A.py looks like
import B
def a():
return B.func()
Now
b_mock.func.return_value = 'spam'
Therefore, A.a() should return 'spam'
However, A.a() returns the entire mock object b_mock like this: < Mock name='mock.B.func()' id='139854736039632' >
Everytime B.func() is called, how do I get the return value which I have set(i.e 'spam') instead of getting the entire mock object?