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.
Related
I have an abstract class with a static function that calls other abstract functions. But when I'm creating a new class and overriding abstract function still the original (abstract) function is running.
I have written an example similar to my problem. Please help.
In the following example, I want to run do_something() from Main not Base.
from abc import ABC, abstractmethod
class Base(ABC):
#staticmethod
#abstractmethod
def do_something():
print('Base')
#staticmethod
def print_something():
Base.do_something()
class Main(Base):
#staticmethod
def do_something():
print('Main')
Main.print_something()
Output:
Base
Main.print_something doesn't exist, so it resolves to Base.print_something, which explicitly calls Base.do_something, not Main.do_something. You probably want print_something to be a class method instead.
class Base(ABC):
#staticmethod
#abstractmethod
def do_something():
print('Base')
#classmethod
def print_something(cls):
cls.do_something()
class Main(Base):
#staticmethod
def do_something():
print('Main')
Main.print_something()
Now when Main.print_something resolves to Base.print_something, it will still receive Main (not Base) as its argument, allowing it to invoke Main.do_something as desired.
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()
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
# parent
class Parent(unittest.TestCase):
#classemthod
def setUpClass(cls):
cls.attr1 = '123'
# real test
class TestMe(Parent):
#classmethod
def setUpClass(cls):
cls.attr2 = '456'
super(Parent, cls).setUpClass()
But if we try to access attr1 from TestMe, the interpreter will say the attribute does not exist.
I also tried to add __init__ in TestMe but didn't help.
Any idea why I can't do this?
Thanks!
You are not using super as you intended. You are asking for the superclass of Parent, so you end up calling unittest.setUpClass, which of course does nothing.
Change it to
#classmethod
def setUpClass(cls):
super(TestMe, cls).setUpClass()
My code:
class TestSystemPromotion(unittest2.TestCase):
#classmethod
def setUpClass(self):
...
self.setup_test_data()
..
def test_something(self):
...
def setup_test_data(self):
...
if __name__ == '__main__':
unittest2.main()
Error which I'm getting is:
TypeError: unbound method setup_test_data() must be called with TestSystemPromotion
instance as first argument (got nothing instead)
You can't call instance methods from class methods. Either consider using setUp instead, or make setup_test_data a class method too. Also, it's better if you called the argument cls instead of self to avoid the confusion - the first argument to the class method is the class, not the instance. The instance (self) doesn't exist at all when setUpClass is called.
class TestSystemPromotion(unittest2.TestCase):
#classmethod
def setUpClass(cls):
cls.setup_test_data()
#classmethod
def setup_test_data(cls):
...
def test_something(self):
...
Or:
class TestSystemPromotion(unittest2.TestCase):
def setUp(self):
self.setup_test_data()
def setup_test_data(self):
...
def test_something(self):
...
For better comprehension, you can think of it this way: cls == type(self)