[Python-Dev] Adding test case methods to TestCase subclasses
Ethan Furman
ethan at stoneleaf.us
Fri Apr 15 21:40:26 CEST 2011
Ben Finney wrote:
> Ethan Furman <ethan at stoneleaf.us> writes:
>
>> Here we have django's TestCase that does *not* want to call
>> unittest2.TestCase (assuming that's not a bug), but it gets called
>> anyway because the Mixin3 sibling has it as a base class. So does
>> this mean that TestCase and Mixin3 just don't play well together?
>>
>> Maybe composition instead of inheritance is the answer (in this case,
>> anyway ;).
>
> TestCase subclasses is a multiple-inheritance use case that I share. The
> mix-ins add test cases (methods named ‘test_’ on the mix-in class) to
> the TestCase subclass. I would prefer not to use multiple inheritance
> for this if it can be achieved in a better way.
>
> How can composition add test cases detectable by Python's ‘unittest’?
Metaclasses, if's that an option...
8<-------------------------------------------------------------
import unittest
from composite import Composite # python 3 only
class Spam():
def test_spam_01(self):
print('testing spam_01')
def test_spam_02(self):
print('testing spam_02')
class Eggs():
def test_eggs_01(self):
print('testing eggs_01')
def test_eggs_02(self):
print('testing eggs_02')
class TestAll(
unittest.TestCase,
metaclass=Composite,
parts=(Spam, Eggs)):
def setUp(self):
print('Setting up...')
def tearDown(self):
print('Tearing down...')
def test_something(self):
print('testing something')
if __name__ == '__main__':
unittest.main()
8<-------------------------------------------------------------
or a class decorator
8<-------------------------------------------------------------
class Compose(object): # python 3 only
def __init__(self, *parts):
self.parts = parts
def __call__(self, func):
for part in self.parts:
for attr in dir(part):
if attr[:2] == attr[-2:] == '__':
continue
setattr(func, attr, getattr(part, attr))
return func
import unittest
class Spam():
def test_spam_01(self):
print('testing spam_01')
def test_spam_02(self):
print('testing spam_02')
class Eggs():
def test_eggs_01(self):
print('testing eggs_01')
def test_eggs_02(self):
print('testing eggs_02')
@Compose(Spam, Eggs)
class TestAll(unittest.TestCase):
def setUp(self):
print('Setting up...')
def tearDown(self):
print('Tearing down...')
def test_something(self):
print('testing something')
if __name__ == '__main__':
unittest.main()
8<-------------------------------------------------------------
The decorator, as written, doesn't work on py2, and doesn't do any error
checking (so overwrites methods in the final class) -- but I'm sure it
could be spiffed up.
~Ethan~
More information about the Python-Dev
mailing list