There are two options to test an abstract base class (ABC) in Python: you can either override or patch the __abstractmethods__ property to be able to instantiate the abstract class and test it directly or you can create a child class that implements all the abstract methods of the base class.
You can not test whole abstract class. In this case you have abstract methods, this mean that they should be implemented by class that extend given abstract class. In that class programmer have to write the source code that is dedicated for logic of his.
test case. A test case is the individual unit of testing. It checks for a specific response to a particular set of inputs. unittest provides a base class, TestCase , which may be used to create new test cases.
I didn't quite understand what do you plan to do -- the rule of thumb is "not to be smart with tests" - just have them there, plain written.
But to achieve what you want, if you inherit from unittest.TestCase, whenever you call unittest.main() your "abstract" class will be executed - I think this is the situation you want to avoid.
Just do this: Create your "abstract" class inheriting from "object", not from TestCase. And for the actual "concrete" implementations, just use multiple inheritance: inherit from both unittest.TestCase and from your abstract class.
import unittest
class Abstract(object):
def test_a(self):
print "Running for class", self.__class__
class Test(Abstract, unittest.TestCase):
pass
unittest.main()
update: reversed the inheritance order - Abstract
first so that its defintions are not overriden by TestCase
defaults, as well pointed in the comments bellow.
There's a very simple way that everyone has missed so far. And unlike several of the answers, it works with all test drivers, rather than failing the minute you switch between them.
Simply use inheritence as usual, then add:
del AbstractTestCase
at the end of the module.
Multiple inheritance isn't a great option here, chiefly for the two following reasons:
TestCase
use super()
so you'd have to list your class first for methods like setUp()
and tearDown()
to work.self.assertEquals()
etc which aren't defined on self
at that point.Here's the kludge I came up with: turn run()
into a no-op for the base class only.
class TestBase( unittest.TestCase ):
def __init__( self, *args, **kwargs ):
super( TestBase, self ).__init__( *args, **kwargs )
self.helper = None
# Kludge alert: We want this class to carry test cases without being run
# by the unit test framework, so the `run' method is overridden to do
# nothing. But in order for sub-classes to be able to do something when
# run is invoked, the constructor will rebind `run' from TestCase.
if self.__class__ != TestBase:
# Rebind `run' from the parent class.
self.run = unittest.TestCase.run.__get__( self, self.__class__ )
else:
self.run = lambda self, *args, **kwargs: None
def newHelper( self ):
raise NotImplementedError()
def setUp( self ):
print "shared for all subclasses"
self.helper = self.newHelper()
def testFoo( self ):
print "shared for all subclasses"
# test something with self.helper
class Test1( TestBase ):
def newHelper( self ):
return HelperObject1()
class Test2( TestBase ):
def newHelper( self ):
return HelperObject2()
If you really want to use inheritance instead of mixins, a simple solution is to nest the abstract test in another class.
It avoids issues with test runner discovery and you can still import the abstract test from another module.
import unittest
class AbstractTests(object):
class AbstractTest(unittest.TestCase)
def test_a(self):
print "Running for class", self.__class__
class Test(AbstractTests.AbstractTest):
pass
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With