I’m wondering what techniques people use for simplifying the ‘size’ of code used for unit testing. For example I was trying to marshal an object of the class and testing the marshal’ed object (but this presumes marshal is working correctly).
Consider the class
import unittest
class Nums(object):
def __init__(self, n1_, n2_, n3_):
self.n1, self.n2, self.n3 = n1_, n2_, n3_
def marshal(self):
return "n1 %g, n2 %g, n3 %g"%(self.n1,self.n2,self.n3)
and then the marshaling based, list based, and normal tests
class NumsTests(unittest.TestCase):
def setUp(self):
self.nu = Nums(10,20,30)
def test_init1(self):
self.assertEquals(self.nu.marshal(),"n1 %g, n2 %g, n3 %g"%(10,20,30))
def test_init2(self):
self.assertEquals([self.nu.n1,self.nu.n2,self.nu.n3],[10,21,31])
def test_init3(self):
self.assertEquals(self.nu.n1,10)
self.assertEquals(self.nu.n2,21)
self.assertEquals(self.nu.n3,31)
which give the following errors (since, 20!=21 and 30!=31, my test has a bad initialization or the test conditions are wrong)
AssertionError: 'n1 10, n2 20, n3 30' != 'n1 10, n2 21, n3 31'
AssertionError: [10, 20, 30] != [10, 21, 31]
AssertionError: 20 != 21
The first and second error messages are difficult to understand (since you have to parse the string or list). However, the 3rd technique rapidly explodes in the amount of code used to test complex objects.
Is there a better way to simplify unit tests without creating difficult error messages? And, without depending on the veracity of a marshal function?
[changed test_marshal to marshal]
For testing initialization, I recommend not testing via calling the
marshal()function. Not only do you then have to parse out which initializer failed, you also have to figure out whether it’s your initialization that’s failing or the marshal function itself. The “minimal style” for unit tests I would recommend is to narrow down the focus of what you’re testing at any test point as much as is feasible.If I really had to test the initialization of a whole bunch of fields, I might refactor much the same way as Eli:
“Good grief,” I can hear you say, “that’s a lot of code!” Well yeah, but the differences are:
assertFieldsEqualandassertFieldEqualare reusable functions that have been abstracted to a common test case class which your other test cases can reuse.When it comes time to test your marshal function, you can simply do this:
When comparing strings, though, I prefer a method that tells me exactly where the strings diverge. For multiline strings, there’s now a method for that in Python 2.7, but I’ve rolled or cribbed my own methods for this purpose in the past.