Using inheritance setUp() and tearDown() methods in nose tests - python

I have a general test class in my nosetests suit and some sub-classes, inheriting from it.
The config is likewise:
class CGeneral_Test(object)::
"""This class defines the general testcase"""
def __init__ (self):
do_some_init()
print "initialisation of general class done!"
def setUp(self):
print "this is the general setup method"
do_setup()
def tearDown(self):
print "this is the general teardown method"
do_teardown()
Now, I have the subclasses which looks like this:
class CIPv6_Test(CGeneral_Test):
"""This class defines the sub, inherited testcase"""
def __init__ (self):
super(CIPv6_Test, self).__init__()
do_some_sub_init()
print "initialisation of sub class done!"
def setUp(self):
print "this is the per-test sub setup method"
do_sub_setup()
def test_routing_64(self):
do_actual_testing_scenarios()
def tearDown(self):
print "this is the per-test sub teardown method"
do_sub_teardown()
So, what I want to achieve would be that each test would invoke both the sub-class and the super class setUp methods.
Hence, the desired order of test is:
Base Setup
Inherited Setup
This is a some test.
Inherited Teardown
Base Teardown
Of course, this can be achieved by calling CGeneral_Test.setUp(self) from the inherited setUp() method.
Is there any configuration in which this behaviour is achieved by default without specifically invoke the super setUp and tearDown methods?
thanks!

No, but you need not specify CGeneral_Test. You didn't in CIPv6_Test.__init__, and you can use the same strategy here:
class CIPv6_Test(CGeneral_Test):
def setUp(self):
super(CIPv6_Test, self).setUp()
print "this is the per-test sub setup method"
do_sub_setup()

Related

unittest.TestCase setUpClass override and inheritance

As can be seen in the following example, I've defined a BaseClass for all tests, each test case class inherits the base class.
Both classes needs to perform a one time initialization, when test_vehicles.py is executed, I need to make sure that setUpClass of the base class is invoked as well, not sure how to achieve that where #classmethod is in play.
# base.py
import unittest
class BaseClass(unittest.TestCase):
#classmethod
def setUpClass(cls):
# initialize stuff
cls.app = app
# test_vehicles.py
class VehiclesTestCase(BaseClass):
#classmethod
def setUpClass(cls):
# initialize stuff
cls.vehicle_id = '123'
def test_get_vehicle(self):
resp = self.app.get(self.vehicle_id)
self.assertEqual(resp, True)
if __name__ == '__main__':
unittest.main()
Similar question Using super with a class method. More information yoou can get also from https://docs.python.org/3/library/functions.html#super.
Solution: use super function and bound to the class
# test_vehicles.py
class VehiclesTestCase(BaseClass):
#classmethod
def setUpClass(cls):
super(VehiclesTestCase, cls).setUpClass()
cls.vehicle_id = '123'
if __name__ == '__main__':
unittest.main()
You can use the super method in the inherited classes' setUpClass to access the setUpClass of BaseClass:
super().setUpClass()
If you don't want to call super in each child class, just create an abstract method in BaseClass and call it in setUpClass of BaseClass. VehiclesTestCase now has to implement this abstract method:
class BaseClass(unittest.TestCase):
#classmethod
def setUpClass(cls):
# initialize stuff
cls.app = app
#classmethod
def _setUpChild(cls):
raise NotImplementedError
class VehiclesTestCase(BaseClass):
#classmethod
def _setUpChild(cls):
# initialize stuff
cls.vehicle_id = '123'
def test_get_vehicle(self):
resp = self.app.get(self.vehicle_id)
self.assertEqual(resp, True)
I would also recommend that BaseClass is not a TestCase if it cannot run by itself. It would always show up in your test report although it has no tests. You can instead use multi-inheritance:
class BaseClass:
# Stuff
class VehiclesTestCase(BaseClass, unittest.TestCase):
# Stuff
The order of inheritance is important. Method lookup is done from left to right. This means that BaseClass.setUpClass overrides the setUpClass of TestCase.

pytest monkeypatch.setattr() inside of test class method

I have a test class with few test methods and I want to patch some app classes and methods from the test methods.
In pytest docs I found an example of how to use monkeypatch module for tests. It that example all tests are just functions, not testclass methods.
But I have a class with test methods:
class MyTest(TestCase):
def setUp():
pass
def test_classmethod(self, monkeypatch):
# here I want to use monkeypatch.setattr()
pass
And just passing monkeypatch as method param is obviously doesn't work. So looks like py.test magic doesn't work this way.
So the question is simple and maybe stupid: how can I use monkeypatch.setattr() for pytest inside from the test class method?
It can't work in this form
While pytest supports receiving fixtures via test function arguments
for non-unittest test methods, unittest.TestCase methods cannot
directly receive fixture function arguments as implementing that is
likely to inflict on the ability to run general unittest.TestCase test
suites.
You might create monkeypatch directly
from _pytest.monkeypatch import MonkeyPatch
class MyTest(TestCase):
def setUp():
self.monkeypatch = MonkeyPatch()
def test_classmethod(self):
self.monkeypatch.setattr ...
...
or create own fixture, which will add monkeypatch to your class, and use #pytest.mark.usefixtures
#pytest.fixture(scope="class")
def monkeypatch_for_class(request):
request.cls.monkeypatch = MonkeyPatch()
#pytest.mark.usefixtures("monkeypatch_for_class")
class MyTest(TestCase):
def setUp():
pass
def test_classmethod(self):
self.monkeypatch.setattr ...
...
I had exactly the same problem.
This works perfectly
import unittest
import pandas as pd
from _pytest.monkeypatch import MonkeyPatch
from src.geipan_data import loadLongitudeLatitudeDateTestimony
class TestGeipanData(unittest.TestCase):
def setUp(self):
self.monkeypatch = MonkeyPatch()
def test_loadLongitudeLatitudeDateTestimony(self):
def read_csv(*args, **kwargs):
return pd.DataFrame({
'obs_date_heure': ['2010-05-21', '1926-05-21'],
'obs_1_lon': [45.123, 78.4564],
'obs_1_lat': [32.123, 98.4564],
})
self.monkeypatch.setattr(pd, 'read_csv', read_csv)
df = loadLongitudeLatitudeDateTestimony()
self.assertListEqual(
df.columns.values.tolist(),
['obs_date_heure', 'obs_1_lon', 'obs_1_lat']
)
In this example I do mock the pd.read_csv method with monkey patch and I uses asserListEqual that extends from unittest.TestCase

mocking in TestCase.setUp()

I want to mock all test methods of a TestCase.
My first try to use TestCase.setUp() did not work, since setUp() finishes before the test methods gets executed.
I can't mock the real test method with this inside setUp():
with mock.patch(...):
do_something()
I guess I am missing something.
How to use mock.patch() for all methods of a test case?
with mock.patch() is a context manager, the patch is unapplied when the context ends, and the context ends at the end of the block of code.
That means that the patches are unapplied again when setUp() ends.
Your options are to either use #mock.patch() as a class decorator or to use the start and stop methods on the patchers.
Using #mock.patch() as a class decorator has the same effect as applying it as a decorator to each and every test method:
#mock.patch('module.ClassName')
class TestFoo(unittest.TestCase):
def setUp(self):
# ...
def test_one(self, class_mock):
# ...
def test_two(self, class_mock):
# ...
Here both test_one and test_two are passed in a mock object because the #mock.patch() class decorator has found all test methods and decorated them.
Using the start and stop methods lets you apply and unapply patches in the setUp and tearDown methods:
class TestFoo(unittest.TestCase):
def setUp(self):
self.patch1 = mock.patch(...)
self.patch1.start()
def tearDown(self):
self.patch1.stop()
Here patch1 is started on set-up, and stopped again when the test is torn down. This acts just like the context manager, but instead hooks into the test boundaries.
Instead of using a tearDown, you can also register the patch.stop() as a cleanup function with TestCase.addCleanup():
class TestFoo(unittest.TestCase):
def setUp(self):
patch1 = mock.patch(...)
patch1.start()
self.addCleanup(patch1.stop)
You can use mock.patch.start, mock.patch.stop. (See patch methods: start and stop).
For example:
class MyTest(TestCase):
def setUp(self):
self.patcher = mock.patch('...')
self.MockClass = self.patcher.start()
def tearDown(self):
self.patcher.stop()
def test_something(self):
....
The most general solution, which works for all context managers is:
import unittest
class TCase(unittest.TestCase):
def setUp(self):
self.cm = mock.path(...)
self.cm.__enter__()
def test1(self):
...
def tearDown(self):
self.cm.__exit__(None, None, None)

Unit tests organisation - how not to run base class tests?

I have tests like this:
import unittest
class TestBase(unittest.TestCase):
def setUp(self):
self.decorator = None
def testA(self):
data = someGeneratorA().generate()
self.assertTrue(self.decorator.someAction(data))
def testB(self):
data = someGeneratorB().generate()
self.assertTrue(self.decorator.someAction(data))
def testC(self):
data = someGeneratorC().generate()
self.assertTrue(self.decorator.someAction(data))
class TestCaseA(TestBase):
def setUp(self):
self.decorator = SomeDecoratorA
class TestCaseB(TestBase):
def setUp(self):
self.decorator = SomeDecoratorB
As you see, TestCaseA and TestCaseB is very similar, so I made TestBase class which implement body of testA, testB and testC method.
TestCaseA different from TestCaseB only decorator parameter.
So, I would like to ask, is any better way to organize my tests? And I have problem beacuse TestBase class - it's test's - shouldn't be runned ever (self.decorator is None so it will rase an exception)
Anything that inherits from unittest.TestCase is seen as a set of tests.
You could instead have your base class not inherit from TestCase, moving that base class to your concrete test classes instead:
class TestBase(object):
# base tests to be reused
class TestCaseA(TestBase, unittest.TestCase):
# Concrete tests, reusing tests defined on TestBase
class TestCaseB(TestBase, unittest.TestCase):
# Concrete tests, reusing tests defined on TestBase

How do I call python subclassed methods from superclass methods?

I have the following kind of superclass / subclass setup:
class SuperClass(object):
def __init__(self):
self.do_something() # requires the do_something method always be called
def do_something(self):
raise NotImplementedError
class SubClass(SuperClass):
def __init__(self):
super(SuperClass, self).__init__() # this should do_something
def do_something(self):
print "hello"
I would like the SuperClass init to always call a not-yet-implemented do_something method. I'm using python 2.7. Perhaps ABC can do this, but it is there another way?
Thanks.
Your code is mostly correct, except for the use of super. You need to put the current class name in the super call, so it would be:
super(SubClass, self).__init__()
Since you put in the wrong class name, SuperClass.__init__ wasn't called, and as a result do_something wasn't called either.

Categories