Friday, February 4, 2011

How to generate dynamic unit tests in python?

I have some kind of test data and want to create an unit test for each item. My first idea was to do it like this:

import unittest

l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]]

class TestSequence(unittest.TestCase):
    def testsample(self):
        for name, a,b in l:
            print "test", name
            self.assertEqual(a,b)

if __name__ == '__main__':
    unittest.main()

The downside of this is that it handles all data in one test. I would like to generate one test for each item on the fly. Any suggestions?

  • i use something like this:

    import unittest
    
    l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]]
    
    class TestSequense(unittest.TestCase):
        pass
    
    def test_generator(a, b):
        def test(self):
            self.assertEqual(a,b)
        return test
    
    if __name__ == '__main__':
        for t in l:
            test_name = 'test_%s' % t[0]
            test = test_generator(t[1], t[2])
            setattr(TestSequense, test_name, test)
        unittest.main()
    
    bignose : -1. This loses one of the main benefits of the `unittest` library: reporting exactly which test failed. When the code in this answer produces a failure, the reported name of the failed test will be identical no matter what the test data. Better is to use a system that generates (and therefore reports) a different name for each test scenario.
    monkut : almost a little to close to black magic for my taste, but better than being a code monkey, thanks!
    From mojo
  • The nose testing framework supports this.

    Example (the code below is the entire contents of the file containing the test):

    param_list = [('a', 'a'), ('a', 'b'), ('b', 'b')]
    
    def test_generator():
        for params in param_list:
            yield check_em, params[0], params[1]
    
    def check_em(a, b):
        assert a == b
    

    The output of the nosetests command:

    > nosetests -v
    testgen.test_generator('a', 'a') ... ok
    testgen.test_generator('a', 'b') ... FAIL
    testgen.test_generator('b', 'b') ... ok
    
    ======================================================================
    FAIL: testgen.test_generator('a', 'b')
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/usr/lib/python2.5/site-packages/nose-0.10.1-py2.5.egg/nose/case.py", line 203, in runTest
        self.test(*self.arg)
      File "testgen.py", line 7, in check_em
        assert a == b
    AssertionError
    
    ----------------------------------------------------------------------
    Ran 3 tests in 0.006s
    
    FAILED (failures=1)
    
    From codeape
  • You would benefit from trying the TestScenarios library.

    testscenarios provides clean dependency injection for python unittest style tests. This can be used for interface testing (testing many implementations via a single test suite) or for classic dependency injection (provide tests with dependencies externally to the test code itself, allowing easy testing in different situations).

    From bignose

0 comments:

Post a Comment