I am using mock from voidspace and trying to execute some tests using unittest2 and the behaviour is strange. When i use "#patch.object(Test,'asd')" as a patch i get the mock object in the function arguments.
If i use #patch.object(Test,'asd',new_fun) as patch i dont get the one of the parameters.
I am using mock-1.0.1
Here you can see a small sample of code that exemplifies the problem.
I want to try to understand if this issue is a problem with the way i do the patch or if this is a problem in the library.
import unittest2 as unittest
from mock import patch
class Test:
def asd(self, a, b =""):
print "1"
class Test1:
def kk(self, l):
Test().asd("1")
def kk1(self, l):
Test().asd("1","1")
#patch.object(Test,'asd')
class MockClassUT(unittest.TestCase):
def test_stat_process(self, my_mock):
t = Test1()
def test_stat_process1(self, my_mock):
t = Test1()
def test_stat_process2(self, my_mock):
t = Test1()
def new_fun(*args, **kwargs):
print "1"
#patch.object(Test,'asd',new_fun)
class MockClassUT1(unittest.TestCase):
def test_stat_process(self, my_mock):
t = Test1()
t.kk("1")
my_mock.assert_called_with("k")
testloader = unittest.TestLoader()
testnames = testloader.getTestCaseNames(MockClassUT)
suite = unittest.TestSuite()
for name in testnames:
suite.addTest(MockClassUT(name))
testnames = testloader.getTestCaseNames(MockClassUT1)
for name in testnames:
suite.addTest(MockClassUT1(name))
print testnames
unittest.TextTestRunner(verbosity=2).run(suite)
This is expected behaviour. You have mocked it as a class decorator and you've also specified the new function new_fun. As such the mocked object won't be passed to each of the methods in the test class.
This means you can't expect my_mock as parameter there and it also means you can't write assertions using my_mock.
Furthermore, as an aside, your mocked method new_fun doesn't have the same signature as the method you're mocking (asd). The method asd expects self, a, b="" whereas new_fun doesn't have arguments so I expect an issue to come up there as well when the mocked method is called.
Related
I am trying to mock a class and also to control the return value of one of the methods. In the MUT the class gets instantiated and I am finding that while the method calls succeed I can not find any way to control the return value.
All the examples I can find show mocking the class methods or mocking a single method with patch object.
I could monkeypatch the entire class and not use Mock, but it seems to me that there must be a way to do this using Mock and have the benefit of all the assert_called*
Here is the simplest example I can come up with that demonstrates the problem. In practice it would be the MUT that instantiates the class but the problem is the same.
from unitest.mock import Mock
mock_class = Mock()
mock_class.method = Mock(return_value=2)
print("Class", mock_class.method(None))
instance = mock_class()
print("Instance", instance.method())
Class 2
Instance <Mock name='mock().method()' id='140446103686160'>
Also tried
from unitest.mock import Mock
mock_class = Mock()
mock_class.method = lambda s: 2
print("Class", mock_class.method(None))
instance = mock_class()
print("Instance", instance.method())
and
from unitest.mock import Mock
mock_class = Mock(method = lambda s: 2)
print("Class", mock_class.method(None))
instance = mock_class()
print("Instance", instance.method())
Same results.
Is there a way to add a method to a Mock class so that it exists in any subsequent instance of the class, or at least control the return value of an instance method for a mocked class?
Mocking a method that is a dependancy is not working for me. When the method I need to test is calling its dependancy method, the real method is called instead of the mock version of it.
I do have the following files:
myLibrary.py
from src.myOtherLibrary import myOtherLibrary
class myLibrary():
def __init__():
self.myVar = myOtherLibrary() #dependancy
def my_method():
method1 = self.method1()
externalMethod2 self.myVar.method2() #method2 called from the external class myOtherLibrary
return method1 + externalMethod2
def method1():
return "method1 from myLibrary..."
src/myOtherLibrary.py
class myOtherLibrary():
def method2():
return "method2 from myOtherLibrary..."
Finally the Unit Test:
TestMyLibrary.py
import unittest
import mock
from myLibrary import myLibrary
from src.myOtherLibrary import myOtherLibrary
class TestMyLibrary(unittest.TestCase):
#mock.patch('myLibrary.myLibrary.method1') #mocking this works because it's a sibling method from my_method() to test
#mock.patch('src.myOtherLibrary.myOtherLibrary.method2') #this does not work because it's an external class from myLibrary
def test_my_method(my_method1_to_mock, my_method2_to_mock):
my_method1_to_mock.return_value = "something_to_return.."
my_method2_to_mock.return_value = "something_else_to_return.."
myLibraryVar = myLibrary()
result = myLibraryVar.my_method()
print result #I would expect to see this: "something_to_return..something_else_to_return.."
#But it actually prints this: "something_to_return..method2 from myOtherLibrary..."
#So mocking is not working for method2
self.assertEqual('something_to_return..something_else_to_return..', result)
if __name__ == '__main__':
unittest.main()
Perhaps it's important to mention that myLibrary.py and TestMyLibrary.py are in the same folder, but myOtherLibrary.py is under different folder level.
I hope you can help me find what I'm missing here.
Any suggestion will be very well appreciated.
Thanks.
You can't patch like that because the methods you are trying to mock are class methods not functions. So you need to use patch.object.
#mock.patch.object(myLibrary, 'method1')
#mock.patch.object(myOtherLibrary, 'method2')
...
Consider example:
def func_b(a):
print a
def func_a():
a = [-1]
for i in xrange(0, 2):
a[0] = i
func_b(a)
And test function that tries to test func_a and mocks func_b:
import mock
from mock import call
def test_a():
from dataTransform.test import func_a
with mock.patch('dataTransform.test.func_b', autospec=True) as func_b_mock:
func_a()
func_b_mock.assert_has_calls([call(0), call(1)])
After func_a has executed I try to test if func_a made correct calls to func_b, but since in for loop I am mutating list in the end I get:
AssertionError: Calls not found.
Expected: [call(0), call(1)]
Actual: [call([1]), call([1])]
The following works (the importing mock from unittest is a Python 3 thing, and module is where func_a and func_b are):
import mock
from mock import call
import copy
class ModifiedMagicMock(mock.MagicMock):
def _mock_call(_mock_self, *args, **kwargs):
return super(ModifiedMagicMock, _mock_self)._mock_call(*copy.deepcopy(args), **copy.deepcopy(kwargs))
This inherits from MagicMock, and redefines the call behaviour to deepcopy the arguments and keyword arguments.
def test_a():
from module import func_a
with mock.patch('module.func_b', new_callable=ModifiedMagicMock) as func_b_mock:
func_a()
func_b_mock.assert_has_calls([call([0]), call([1])])
You can pass the new class into patch using the new_callable parameter, however it cannot co-exist with autospec. Note that your function calls func_b with a list, so call(0), call(1) has to be changed to call([0]), call([1]). When run by calling test_a, this does nothing (passes).
Now we cannot use both new_callable and autospec because new_callable is a generic factory but in our case is just a MagicMock override. But Autospeccing is a very cool mock's feature, we don't want lose it.
What we need is replace MagicMock by ModifiedMagicMock just for our test: we want avoid to change MagicMock behavior for all tests... could be dangerous. We already have a tool to do it and it is patch, used with the new argument to replace the destination.
In this case we use decorators to avoid too much indentation and make it more readable:
#mock.patch('module.func_b', autospec=True)
#mock.patch("mock.MagicMock", new=ModifiedMagicMock)
def test_a(func_b_mock):
from module import func_a
func_a()
func_b_mock.assert_has_calls([call([0]), call([1])])
Or:
#mock.patch("mock.MagicMock", new=ModifiedMagicMock)
def test_a():
with mock.patch('module.func_b') as func_b_mock:
from module import func_a
func_a()
func_b_mock.assert_has_calls([call([0]), call([1])])
Why does calling a method like this in ironPython work?:
from System.Collections.Generic import List
class test:
mem = None
def __init__(self):
# !No Instance created !!!
self.mem = List[int]
def doSomeThing(self):
if self.mem.Contains((List[int](), 123):
pass
I can't get the behaviour of IronPython in this case: self.mem.Contains((List[int](), 123):. Does any one has an explanation for this?
EDIT
Is self.mem only the type, and Contains will always return False? If this is true, it seems to be a nice feature :)
Thank you!
This is true of normal Python classes as well:
class Foo(object):
def bar(self):
pass
f = Foo
f.bar(Foo())
It's the difference between bound (Foo().bar) and unbound (Foo.bar) methods. It's not so much a feature as a side effect of how methods are implemented in Python.
Contains is always false because it is working on an empty list, which contains nothing.
I want to check that do_a calls do_b. I'm doing like this:
The code:
def do_a(...):
...
do_b(...)
...
The test:
def test_do_a(self):
...
with patch('...do_b', new_callable=do_nothing()) as mock_do_b:
do_a(...)
mock_do_b.assert_called_once_with(...)
And do_nothing:
def do_nothing():
pass
This is working fine but I had to use do_nothing() which I find hacky. Is there a way to make the same test without the extra useless function do_nothing()?
You could use patch as a decorator
#patch('...do_b')
def test_do_a(self, mock_do_b):
do_a(...)
mock_do_b.assert_called_once_with(...)