views:

89

answers:

4
+2  Q: 

Python Unittest

I am using python unittest module to do a number of tests; however, it is very repetitive.

I have a lot of data that I want to run through the same test over and over, checking if correct. However, I have to define a test for every one.

For instance I want to do something similar to this. I know I could do it using a generator (found it in a previous thread here). But are there alternatives, maybe even using a different testing module?

Any suggestions would be great.


import unittest

class TestData(unittest.TestCase):
    def testNumbers(self):
        numbers = [0,11,222,33,44,555,6,77,8,9999]
        for i in numbers:
            self.assertEqual(i, 33)
+1  A: 

The problem with running assertions in a loop is that, if one of the assertions fails, you don't know which value caused it (in your example, it would fail on 0, but you don't know that until you debug). On the other hand, repeating self.assertEqual(i, 33) is an even worse idea, because it introduces code duplication.

What I do in my test is to create a simple, shortly-named internal function inside the test and call it with different arguments. So your function would look like this:

import unittest

class TestData(unittest.TestCase):
    def testNumbers(self):
        def eq(i):
            self.assertEqual(i, 33)
        eq(0)
        eq(11)
        eq(222)
        eq(33)
        eq(44)
        eq(555)
        ... 

This way, when the assertion fails for 0, you immediately see it on the stack trace printed by the unittest module.

DzinX
I see what you are doing. Its a good idea. But the first time it hits 33, it will stop executing for the rest of the code.
Mark
If what you're saying is that you have to recreate the test fixture for each number, then you should go ahead with what Bill Gribble suggested and dynamically construct a TestSuite.
DzinX
+2  A: 

You may want to consider using the unittest.TestSuite class, which will allow you to dynamically construct a set of unittest.TestCase instances which will get run separately. Your unittest.TestCase subclass should define just one test method, with the class accepting a construction parameter passing in the value to test against for that particular instance.

Bill Gribble
A: 

Sample code for solution suggested by Bill Gribble would could like this:

import unittest

class DataTestCase(unittest.TestCase):
    def __init__(self, number):
        unittest.TestCase.__init__(self, methodName='testOneNumber')
        self.number = number

    def testOneNumber(self):
        self.assertEqual(self.number, 33)

    def shortDescription(self):
        # We need to distinguish between instances of this test case.
        return 'DataTestCase for number %d' % self.number


def get_test_data_suite():
    numbers = [0,11,222,33,44,555,6,77,8,9999]
    return unittest.TestSuite([DataTestCase(n) for n in numbers])

if __name__ == '__main__':
    testRunner = unittest.TextTestRunner()
    testRunner.run(get_test_data_suite())
DzinX
A: 

In another post I stumbled accross Nose Tests It is more suited to data driven testing.


class Test_data():
    def testNumbers():
        numbers = [0,11,222,33,44,555,6,77,8,9999]
        for i in numbers:
            yield checkNumber, num

def checkNumber(num):
    assert num == 33

The above code does the exact same thing as my first post. No imports are needed, just write a python class.

You execute the tests by typing:

nosetests filename

Mark