There's a simple change that could be made to unittest that would make it easier to automate some forms of testing.
I want to be able to dynamically add tests to an instance of a class derived from unittest.TestCase. There are occasions when I don't want to write my tests upfront in a Python file. E.g., given a bunch of test/expectedResult data sitting around (below in a variable named MyTestData), it would be nice to be able to do the following (untested here, but I did it earlier for real and it works fine):
class Test(unittest.TestCase): def runTest(): pass
suite = unittest.TestSuite()
for testFunc, expectedResult in MyTestData: newTestFuncName = 'dynamic-test-' + testFunc.__name__ def tester(): self.assertEqual(testFunc(), expectedResult) test = Test() setattr(test, newTestFuncName, tester) # Set the class instance up so that it will be the one run. test.__init__(newTestFuncName) # ugh! suite.addTest(test)
The explicit call to __init__ (marked ugh!) is ugly, dangerous, etc. You could also say test._testMethodName = newTestFuncName (and set _testMethodDoc too), but that's also ugly.
This would all be very simple though if instead of starting out like:
class TestCase: def __init__(self, methodName='runTest'): try: self._testMethodName = methodName testMethod = getattr(self, methodName) self._testMethodDoc = testMethod.__doc__ except AttributeError: raise ValueError, "no such test method in %s: %s" % \ (self.__class__, methodName)
unittest.TestCase started out like this:
class TestCase: def __init__(self, methodName='runTest'): self.setTestMethod(methodName)
def setTestMethod(self, methodName): try: self._testMethodName = methodName testMethod = getattr(self, methodName) self._testMethodDoc = testMethod.__doc__ except AttributeError: raise ValueError, "no such test method in %s: %s" % \ (self.__class__, methodName)
That would allow people to create an instance of their Test class, add a method to it using setattr, and then use setTestMethod to set the method to be run.
A further improvement would be to have _testMethodName be None or left undefined (and accessed via __getattr__) for as long as possible rather than being set to runTest (and looked up with getattr) immediately. That would allow the removal of the do-nothing runTest method in the above. No old code need be broken as runTest would still be the default. You'd just have a chance to get in there earlier so it never saw the light of day.
Programmers like to automate things, especially testing. These changes don't break any existing code but they allow additional test automation. Of course you _could_ achieve the above by writing out a brand new temp.py file, running it, and so on, but that's not very Pythonic, is a bunch more work, needs cleanup (temp.py needs to go away), etc.
I have some further thoughts about how to make this a bit more flexible, but I'll save those for later, supposing there's any interest in the above.