decorators to add test* TestCase methods

Peter Otten __peter__ at web.de
Fri Jan 27 08:12:38 EST 2006


Bruce Cropley wrote:

> I'm trying to generate test methods in a unittest TestCase
> subclass, using decorators.  I'd like to be able to say:
> 
> class MyTestCase(unittest.TestCase):
>     @genTests(["Buy", "Sell"], [1,2,3], [True, False])
>     def something(self, side, price, someFlag):
>         # etc...
> 
> And have it generate functions called:
>     test_Buy_1_True_something
>     test_Buy_1_False_something
> through to...
>     test_Sell_3_False_something

I think that's a nice idea. Here is a preliminary implementation:

#!/usr/bin/env python
import unittest

def combine(axes):
    if axes:
        for value in axes[0]:
            for rest in combine(axes[1:]):
                yield (value,) + rest
    else:
        yield ()

def make_method(func, name, args):
    def method(self):
        return func(self, *args)
    method.__name__ = name
    return method

class TestGrid(object):
    def __init__(self, func, axes):
        self.func = func
        self.axes = axes
    def __iter__(self):
        axes = self.axes
        func = self.func
        name_format = "_".join(("test", self.func.__name__) +
("%s",)*len(axes))
        for values in combine(axes):
            name = name_format % values
            yield name, make_method(func, name, values)

class genTests:
    def __init__(self, *axes):
        self.axes = axes
    def __call__(self, func):
        return TestGrid(func, self.axes)

class GridTestCase(unittest.TestCase):
    class __metaclass__(type):
        def __new__(mcl, clsname, bases, dict):
            for name, value in dict.items():
                if isinstance(value, TestGrid):
                    for method_name, method in value:
                        if method_name in dict:
                            raise Exception("name clash")
                        dict[method_name] = method
            return type.__new__(mcl, clsname, bases, dict)


class MyTestCase(GridTestCase):
    @genTests(["Buy", "Sell"], [1,2,3], [True, False])
    def something(self, side, price, someFlag):
        pass #print "test(side=%r, price=%r, someFlag=%r)" % (side, price,
someFlag)

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




More information about the Python-list mailing list