Pages

Monday, 25 April 2011

In python unittest the setUp function gets called every time you need to run a single TestCase (no matter if you run it using TestSuite or simply unittest.main()).

So if you have to test something that requires a complex setUp routine (like loading 50000 records from SQL or preparing an orangemochafrappuccino) but that can be reused all along your TestSuite you have the same problem I had.

Now all around the internet there are posts saying "You could do that" or "One way to do that" or "Once I did that like this..." or even worse "The standard way of doing it is...".

But none of these posts really gets to the bottom of it, they all give you a piece of information. I couldn't find one place that told you "copy/paste this code and be happy".

So, after figuring it out, I can now tell you "copy/paste this code and be happy".

import unittest
from my_program import MyClass
class MyClassTest(unittest.TestCase):
# First define a class variable that determines
# if setUp was ever run
ClassIsSetup = False
def setUp(self):
# If it was not setup yet, do it
if not self.ClassIsSetup:
print "Initializing testing environment"
# run the real setup
self.setupClass()
# remember that it was setup already
self.__class__.ClassIsSetup = True
def setupClass(self):
# Do the real setup
unittest.TestCase.setUp(self)
# you want to have persistent things to test
self.__class__.myclass = MyClass()
# (you can call this later with self.myclass)

You can do the same for the unittest.tearDown since it is exactly the same code.

and you want to test this and moreover you want that search to return a given set of data.

from minimock import Mock
import ldap
from my_program import MyClass
class MyClassTest(unittest.TestCase):
...
def test_ldapsearch(self):
# create your fake ldap connection
ldap.open = Mock('ldap.open')
ldap.open.mock_returns = Mock('ldap_connection')
# instantiate your class
myclass = MyClass()
# now tell to minimock that in case we do a search_s on
# a conn method this should be intercepted and mocked
# returning a testuser1 value the way LDAP would do
myclass.conn.search_s.mock_returns = [[1,{'uid':['testuser1'], \
'mail':['test.user1@mail.com']}]]
# This will return testuser1 no matter what
# and show you on screen the operations performed
self.assertEqual(myclass.ldapsearch('onetwoonetwo'), True)

This should help you inject whatever values you want there and also clarify a bit how to minimock wants you to think (that is the only way I could make it work).