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() -- http://mail.python.org/mailman/listinfo/python-list