I am trying to mock the super class of a class with a setup similar to this:
File parent.py
class Parent:
def write(self):
*some code*
File child.py
class Child(Parent):
def write(self):
*more code*
super().write()
File mock_parent.py
class MockParent(Parent):
def write(self):
...
My goal would be to replace Parent with MockParent to improve testing of Child, by eliminating real hardware resources.
So far I tried to use mock patch with no success. I tried to patch imports, bases and super but none of these attempts had been successful. I could replace the internals of the Child object, but I would prefer to have a cleaner solution through patching potentially.
The biggest challenge is that the call to the method write of the parent class (by super().write()) is inside the subclass method, otherwise I could simply assign it the function I want to be called.
In this moment I have found this solution which needs a change to the code of the method write of the class Child. This modification must be used only during the test, while, in production code you have to used your production code.
Below I show you the file test_code.py which contains the production code and the test code:
import unittest
from unittest.mock import Mock
class Parent:
def write(self):
print("parent.write()")
class Child(Parent):
def write(self, *super_class):
print("child.write()")
# ----> Here I have changed your code
if len(super_class) > 0:
super_class[0].write()
else:
# ----> ... here you find your production code
super().write()
class MockParent(Parent):
def write(self):
print("mock_parent.write()")
class MyTestCase(unittest.TestCase):
def test_with_parent_mock(self):
print("Execution of test_with_parent_mock")
mock_parent = Mock(wraps = MockParent())
child = Child()
child.write(mock_parent)
mock_parent.write.assert_called_once()
def test_with_parent(self):
print("Execution of test_with_parent")
child = Child()
child.write()
if __name__ == '__main__':
unittest.main()
If you execute this code by the command python test_code.py, you will obtain the following output:
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
Execution of test_with_parent
child.write()
parent.write()
Execution of test_with_parent_mock
child.write()
mock_parent.write()
The output of the test method test_with_parent_mock() shows that you can substitute the write() method of the super class with an other method defined in MockParent.
Instead in the method test_with_parent() you can call the write() method of the class Child normally.
Note about TDD
What I have proposed to you is only a workaround, but I don't know if it is suited to reach your goal because I see that between the tags selected by you, there is TDD. However I hope this code could be useful for you.
Related
I have some code that creates instances from a list of classes that is passed to it. This cannot change as the list of classes passed to it has been designed to be dynamic and chosen at runtime through configuration files). Initialising those classes must be done by the code under test as it depends on factors only the code under test knows how to control (i.e. it will set specific initialisation args). I've tested the code quite extensively through running it and manually trawling through reams of output. Obviously I'm at the point where I need to add some proper unittests as I've proven my concept to myself. The following example demonstrates what I am trying to test:
I would like to test the run method of the Foo class defined below:
# foo.py
class Foo:
def __init__(self, stuff):
self._stuff = stuff
def run():
for thing in self._stuff:
stuff = stuff()
stuff.run()
Where one (or more) files would contain the class definitions for stuff to run, for example:
# classes.py
class Abc:
def run(self):
print("Abc.run()", self)
class Ced:
def run(self):
print("Ced.run()", self)
class Def:
def run(self):
print("Def.run()", self)
And finally, an example of how it would tie together:
>>> from foo import Foo
>>> from classes import Abc, Ced, Def
>>> f = Foo([Abc, Ced, Def])
>>> f.run()
Abc.run() <__main__.Abc object at 0x7f7469f9f9a0>
Ced.run() <__main__.Abc object at 0x7f7469f9f9a1>
Def.run() <__main__.Abc object at 0x7f7469f9f9a2>
Where the list of stuff to run defines the object classes (NOT instances), as the instances only have a short lifespan; they're created by Foo.run() and die when (or rather, sometime soon after) the function completes. However, I'm finding it very tricky to come up with a clear method to test this code.
I want to prove that the run method of each of the classes in the list of stuff to run was called. However, from the test, I do not have visibility on the Abc instance which the run method creates, therefore, how can it be verified? I can't patch the import as the code under test does not explicitly import the class (after all, it doesn't care what class it is). For example:
# test.py
from foo import Foo
class FakeStuff:
def run(self):
self.run_called = True
def test_foo_runs_all_stuff():
under_test = Foo([FakeStuff])
under_test.run()
# How to verify that FakeStuff.run() was called?
assert <SOMETHING>.run_called, "FakeStuff.run() was not called"
It seems that you correctly realise that you can pass anything into Foo(), so you should be able to log something in FakeStuff.run():
class Foo:
def __init__(self, stuff):
self._stuff = stuff
def run(self):
for thing in self._stuff:
stuff = thing()
stuff.run()
class FakeStuff:
run_called = 0
def run(self):
FakeStuff.run_called += 1
def test_foo_runs_all_stuff():
under_test = Foo([FakeStuff, FakeStuff])
under_test.run()
# How to verify that FakeStuff.run() was called?
assert FakeStuff.run_called == 2, "FakeStuff.run() was not called"
Note that I have modified your original Foo to what I think you meant. Please correct me if I'm wrong.
Like many people, I'm having issues with mock patching and getting the path right. Specifically, my code references another class in the same file and I'm having trouble patching that reference.
I have the following python file, package/engine/dataflows/flow.py:
class Flow:
def run(self, type):
if type == 'A':
method1()
elif type == 'B':
method2()
else:
backfill = Backfill()
backfill.run()
class Backfill(Flow):
def run(self):
...
And a test file package/tests/engine/dataflows/test_Flow.py
import unittest
from unittest.mock import Mock, patch
from engine.dataflows.flow import Flow
class MockFlow(Flow):
...
class TestFlowRun(unittest.TestCase):
def setUp(self):
self.flow = MockFlow()
def test_run_type_c(self):
with patch('engine.dataflows.flow.Backfill') as mock_backfill:
self.flow.run(type='C')
assert mock_backfill.run.call_count == 1
The patch works in that it doesn't throw an error when run with pytest, but the assertion is failing. I assume that is because the local reference to the Backfill class has essentially already been imported when MockFlow was initialized, but I have been unable to come up with a patching path that handles this.
The contents of flow.py include the Flow base class and a couple of child classes that implement different data flow patterns. They're co-located in the same file for ease of understanding and common dependencies.
The problem is that you are checking the run() function of a class, not an instantiation of that class. The mocked Backfill class will return an instance of the class via its constructor/init. That is the mock / object you will want to check.
with patch('engine.dataflows.flow.Backfill') as mock_backfill:
mocked_backfill_instance = mock_backfill.return_value
self.flow.run(type='C')
assert mocked_backfill_instance.run.call_count == 1
In a hobby project I intend to use nose for testing, I want to put all tests for specific classes into classes since these tests share setup and other functionality. But I can't seem to get nose to execute the setup methods inside the classes.
Here is an example class that is tested:
class mwe():
def __init__(self):
self.example = ""
def setExample(self, ex):
self.example = ex
The tests work, when I don't use classes:
from nose.tools import ok_
import mwe
exampleList = []
def setUp():
print("setup")
exampleList.append("1")
exampleList.append("2")
exampleList.append("3")
def test_Example():
print("test")
for ex in exampleList:
t = mwe.mwe()
t.setExample(ex)
yield check, t, ex
def check(e, ex):
ok_(e.example == ex)
The output is as expected:
setup
test
...
----------------------------------------------------------------------
Ran 3 tests in 0.004s
OK
When a test class is used, the setup method is not executed and therefore no tests are executed.
from nose.tools import ok_
import mwe
class TestexampleClass(object):
def __init__(self):
print("__init__")
self.exampleList = []
def setup(self):
print("setup class")
self.exampleList.append("1")
self.exampleList.append("2")
self.exampleList.append("3")
def test_ExampleClass(self):
print("test class")
for ex in self.exampleList:
t = mwe.mwe()
t.setExample(ex)
yield self.check, t, ex
def check(self, we, ex):
print("check class")
ok_(we.example == ex)
I'm fairly new to python and a newbie with nose, my question is, why is setup not executed? Where is the error in my code?
__init__
test class
----------------------------------------------------------------------
Ran 0 tests in 0.002s
OK
I will be glad for any feedback.
When I use the code from this Question on SO the setup method is executed, as I would expect it.
SOLUTION: After a lot of desperation I found the following:
Nose executes the the class level setup method before the execution of the yielded function, not when the test_* methods are called, as I expected and as is the case for other test_* methods. This obviously goes against the nose documentation:
Setup and teardown functions may be used with test generators. However, please note that setup and teardown attributes attached to the generator function will execute only once. To execute fixtures for each yielded test, attach the setup and teardown attributes to the function that is yielded, or yield a callable object instance with setup and teardown attributes.
Looking at the bug reports, I found the bug report on github.
A possible workaround is to use class level fixtures:
#classmethod
def setup_class(cls):
#do stuff
pass
Your test class needs to extend TestCase and the setup method needs to be called setUp
from unittest import TestCase
class TestUtils(TestCase):
def setUp(self):
self.x = 1
def test_something(self):
self.assertEqual(1, self.x)
which outputs
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
I'm trying to run a TestCase in python 3.3.2 that has several test methods in it:
class ttt(unittest.TestCase):
def setUp(self):
...
def tearDown(self):
...
def test_test1(self):
...
def test_test2(self):
...
if __name__ == "__main__":
instance = ttt()
instance.run()
The documentation states the following:
Each instance of TestCase will run a single base method: the method
named methodName. However, the standard implementation of the default
methodName, runTest(), will run every method starting with test as an
individual test, and count successes and failures accordingly.
Therefore, in most uses of TestCase, you will neither change the
methodName nor reimplement the default runTest() method.
However, when I run the code I get the following:
'ttt' object has no attribute 'runTest'
I want to ask: Is this a bug? And if it's not why is there no runTest method? Am I doing something wrong?
When the unit test framework runs test cases, it creates an instance of the test class for each test.
I.e. to simulate what the unit test framework does you need to do:
if __name__ == "__main__":
for testname in ["test_test1", "test_test2"]:
instance = ttt(testname)
instance.run()
The correct way to run unit tests in a module is:
if __name__ == "__main__":
unittest.main()
... but I assume you know this already.
Regarding runTest: unittest.TestCase.__init__ signature and docstring is:
def __init__(self, methodName='runTest'):
"""Create an instance of the class that will use the named test
method when executed. Raises a ValueError if the instance does
not have a method with the specified name.
"""
Meaning that if you don't specify a test name in the constructor, the default is runTest.
After reading about testing private methods in Python, specifically referring to this accepted answer, it appears that it is best to just test the public interface. However, my class looks like this:
class MyClass:
def __init__(self):
# init code
def run(self):
self.__A()
self.__B()
self.__C()
self.__D()
def __A(self):
# code for __A
def __B(self):
# code for __B
def __C(self):
# code for __C
def __D(self):
# code for __D
Essentially, I created a class to process some input data through a pipeline of functions. In this case, it would be helpful to test each private function in turn, without exposing them as public functions. How does one go about this, if a unit test can't execute the private function?
Python does some name mangling when it puts the actually-executed code together. Thus, if you have a private method __A on MyClass, you would need to run it like so in your unit test:
from unittest import TestCase
class TestMyClass(TestCase):
def test_private(self):
expected = 'myexpectedresult'
m = MyClass()
actual = m._MyClass__A
self.assertEqual(expected, actual)
The question came up about so-called 'protected' values that are demarcated by a single underscore. These method names are not mangled, and that can be shown simply enough:
from unittest import TestCase
class A:
def __a(self):
return "myexpectedresult"
def _b(self):
return "a different result"
class TestMyClass(TestCase):
def test_private(self):
expected = "myexpectedresult"
m = A()
actual = m._A__a()
self.assertEqual(expected, actual)
def test_protected(self):
expected = "a different result"
m = A()
actual = m._b()
self.assertEqual(expected, actual)
# actual = m._A__b() # Fails
# actual = m._A_b() # Fails
First of all, you CAN access the "private" stuff, can't you? (Or am I missing something here?)
>>> class MyClass(object):
... def __init__(self):
... pass
... def __A(self):
... print('Method __A()')
...
>>> a=MyClass()
>>> a
<__main__.MyClass object at 0x101d56b50>
>>> a._MyClass__A()
Method __A()
But you could always write a test function in MyClass if you have to test the internal stuff:
class MyClass(object):
...
def _method_for_unit_testing(self):
self.__A()
assert <something>
self.__B()
assert <something>
....
Not the most elegant way to do it, to be sure, but it's only a few lines of code at the bottom of your class.
Probably you should just test the run() method. Most classes will have internal methods -- and it does not really matter in this case whether or not all the code in __A(), __B(), __C,() and __D() is actually in run() or not. If you suspect or find problems, then you might want to switch to your debugger aspect and test the private methods.