views:

230

answers:

2

How can I make python's unittest module show output for every assertion, rather than failing at the first one per test case? It would be much easier to debug if I could see the complete pattern of failures rather than just the first one.

In my case the assertions are based on a couple loops over an array containing an object plus some function names and the expected output (see below), so there isn't an obvious way (at least to me) to just separate every assertion into a separate TestCase:

import unittest
import get_nodes

class mytest2(unittest.TestCase):
    def testfoo(self):
        root = get_nodes.mmnode_plus.factory('mytree.xml')

        tests = [
            (root, {'skip_traversal': False, 'skip_as_child': True, 'skip_as_parent': False, 'is_leaf': False}),
            (root[0], {'skip_traversal': False, 'skip_as_child': False, 'skip_as_parent': False, 'is_leaf': False}),
            (root[1], {'skip_traversal': True, 'skip_as_child': True, 'skip_as_parent': True}),
            (root[1][0], {'skip_traversal': True}),
            (root[0][0], {'is_leaf': False, 'skip_traversal': False, 'skip_as_child': False, 'skip_as_parent': False}),
            (root[0][0][0], {'is_leaf': True, 'skip_traversal': False, 'skip_as_child': False, 'skip_as_parent': True}),
            (root[0][4], {'skip_traversal': True, 'skip_as_child': True, 'skip_as_parent': True}),
            (root[0][7], {'skip_traversal': False, 'skip_as_child': False, 'skip_as_parent': True}),
        ]       

        for (node, states) in tests:
            for test_state, exp_result in states.iteritems():
                self.assertEqual(node.__getattribute__(test_state)(), exp_result, "unexpected %s for state %s of node %s %s" % (not exp_result, test_state, repr(node), repr(node.__dict__)))

unittest.main()

obj.getattribute('hello') returns obj.hello so node.__getattribute__(test_state)() is my way of calling the member function of node whose name is stored in the test_state variable.

+2  A: 
import unittest
import get_nodes

class TestSuper(unittest.TestCase):
    def setUp( self ):
        self.root = get_nodes.mmnode_plus.factory('mytree.xml')
    def condition( self, aNode, skip_traversal, skip_as_child, skip_as_parent, is_leaf ):
        self.assertEquals( skip_traversal, aNode.skip_traversal )
        self.assertEquals( skip_as_child, aNode. skip_as_child)
        self.assertEquals( skip_as_parent, aNode. skip_as_parent)
        self.assertEquals( is_leaf , aNode. is_leaf )

class TestRoot( TestSuper ):
    def testRoot( self ):
        self.condition( self.root, **{'skip_traversal': False, 'skip_as_child': True, 'skip_as_parent': False, 'is_leaf': False} )

class TestRoot0( TestSuper ):
    def testRoot0( self ):
        self.condition( self.root[0], **{'skip_traversal': False, 'skip_as_child': False, 'skip_as_parent': False, 'is_leaf': False} )

class TestRoot1( TestSuper ):
    def testRoot1( self ):
        self.condition( self.root[1], **{'skip_traversal': True, 'skip_as_child': True, 'skip_as_parent': True})

class TestRoot10( TestSuper ):
    def testRoot10( self ):
        self.condition( self.root[1][0], **{'skip_traversal': True})

class TestRoot00( TestSuper ):
    def testRoot00( self ):
        self.condition( self.root[0][0], **{'is_leaf': False, 'skip_traversal': False, 'skip_as_child': False, 'skip_as_parent': False})

class TestRoot0( TestSuper ):
    def testRoot000( self ):
        self.condition( root[0][0][0], **{'is_leaf': True, 'skip_traversal': False, 'skip_as_child': False, 'skip_as_parent': True})

class TestRoot04( TestSuper ):
    def testRoot04( self ):
        self.condition( self.root[0][4], **{'skip_traversal': True, 'skip_as_child': True, 'skip_as_parent': True})

class TestRoot07( TestSuper ):
    def testRoot07( self ):
        self.condition( self.root[0][7], **{'skip_traversal': False, 'skip_as_child': False, 'skip_as_parent': True})

unittest.main()
S.Lott
couldn't something like this be generated dynamically from the same array?
ʞɔıu
@ʞɔıu: Since I have no patience with metaclasses, my answer is no. It's entirely possible to create a metaclass which spawns all these individual classes from a list of values. It's entirely possible to use Jinja templates to generate it also. Tests MUST be simple, so I prefer copy and paste.
S.Lott
+1  A: 

I was able to do it by making new TestCase classes dynamically using the builtin type() factory:

root = get_nodes.mmnode_plus.factory('somenodes.xml')

tests = [
    (root, {'skip_traversal': False, 'skip_as_child': True, 'skip_as_parent': False, 'is_leaf': False}),
    (root[0], {'skip_traversal': False, 'skip_as_child': False, 'skip_as_parent': False, 'is_leaf': False}),
    (root[1], {'skip_traversal': True, 'skip_as_child': True, 'skip_as_parent': True}),
    (root[1][0], {'skip_traversal': True}),
    (root[0][0], {'is_leaf': False, 'skip_traversal': False, 'skip_as_child': False, 'skip_as_parent': False}),
    (root[0][0][0], {'is_leaf': True, 'skip_traversal': False, 'skip_as_child': False, 'skip_as_parent': True}),
    (root[0][4], {'skip_traversal': True, 'skip_as_child': True, 'skip_as_parent': True}),
    (root[0][7], {'skip_traversal': False, 'skip_as_child': False, 'skip_as_parent': True}),
]

i = 0
for (node, states) in tests:
    for test_state, exp_result in states.iteritems():

        input = node.__getattribute__(test_state)()
        errstr = "expected %s, not %s for state %s of node %s" % (input, exp_result, test_state, repr(node))

        locals()['foo' + str(i)] = type('foo' + str(i), (unittest.TestCase,),
            {'input': input, 'exp_result': exp_result, 'errstr': errstr, 'testme': lambda self: self.assertEqual(self.input, self.exp_result, self.errstr)})
        i += 1
ʞɔıu