Computing test methods in unittest.TestCase

J

Jan Decaluwe

I'm working on a unit test for a finite state machine (FSM). The FSM
behavior is specified in a dictionary called transitionTable. It has a
key per state with a tuple of possible transitions as the corresponding
value. A transition is defined as a number of input values, a next
state, and a documentation string.

I want to test each possible transition in a separate test method. For
a particular transition, a test method could look as follows:

class FSMTest(unittest.TestCase):
....
def test_START_2(self):
"""Check state START - Switched channels before data started"""
state, transition = START, transitionTable[START][2]
sim = Simulation(self.bench(state, transition))
sim.run()

As the number of transitions can be large, I want to
"compute" the test methods, based on the transitionTable info.
Currently, I have the following:

class FSMTest(unittest.TestCase):
....
for st, trs in transitionTable.items():
for i, tr in enumerate(trs):
def _tmpfunc(self, st=st, tr=tr):
sim = Simulation(self.bench(st, tr))
sim.run()
_tmpfunc.func_doc = "Check state %s - %s" % (st, getDoc(tr))
exec "test_%s_%s = _tmpfunc" % (st, i)

This works, but uses some "ugly" tricks:

* default arguments to pass context info. As the code is executed in
class context, not function context, I cannot use free variables.
* The use of 'exec'. unittest looks for methods with name prefix
'test_' in the class namespace, and I didn't find another way
to achieve that.

Anyone with better ideas?
 
J

James Kew

Jan Decaluwe said:
....
for st, trs in transitionTable.items():
for i, tr in enumerate(trs):
def _tmpfunc(self, st=st, tr=tr):
sim = Simulation(self.bench(st, tr))
sim.run()
_tmpfunc.func_doc = "Check state %s - %s" % (st, getDoc(tr))
exec "test_%s_%s = _tmpfunc" % (st, i)

This works, but uses some "ugly" tricks:

* default arguments to pass context info. As the code is executed in
class context, not function context, I cannot use free variables.
* The use of 'exec'. unittest looks for methods with name prefix
'test_' in the class namespace, and I didn't find another way
to achieve that.

Anyone with better ideas?

Define the test methods after defining the class, and inject them into the
class with setattr:

class testClass:
pass

def makeTest(param):
def test(self):
print "test: param=%s" % param
return test

setattr(testClass, "test1", makeTest(1))
setattr(testClass, "testHello", makeTest("Hello"))
test: param=Hello

James
 
P

Peter Otten

Jan said:
I'm working on a unit test for a finite state machine (FSM). The FSM
behavior is specified in a dictionary called transitionTable. It has a
key per state with a tuple of possible transitions as the corresponding
value. A transition is defined as a number of input values, a next
state, and a documentation string.

I want to test each possible transition in a separate test method. For
[...]

As the number of transitions can be large, I want to
"compute" the test methods, based on the transitionTable info.
[...]

Anyone with better ideas?

Use a test suite instead and turn each FSMTest.testXXX() method into a
TestCase instance:

class TransitionTest(unittest.TestCase):
def __init__(self, state, transition):
unittest.TestCase.__init__(self)
self.state = state
self.transition = transition

def bench(self, state, transition):
pass

def runTest(self):
Simulation(self.bench(self.state, self.transition)).run()

def __str__(self):
return "Check state %s - %s" % (self.state, getDoc(self.transition))

def makeSuite():
suite = unittest.TestSuite()
for st, trs in transitionTable.iteritems():
for tr in trs:
suite.addTest(TransitionTest(st, tr))
return suite

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

Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top