views:

633

answers:

3

I currently have a unittest.TestCase that looks like..

class test_appletrailer(unittest.TestCase):
    def setup(self):
        self.all_trailers = Trailers(res = "720", verbose = True)

    def test_has_trailers(self):
        self.failUnless(len(self.all_trailers) > 1)

    # ..more tests..

This works fine, but the Trailers() call takes about 2 seconds to run.. Given that setUp() is called before each test is run, the tests now take almost 10 seconds to run (with only 3 test functions)

What is the correct way of caching the self.all_trailers variable between tests?

Removing the setUp function, and doing..

class test_appletrailer(unittest.TestCase):
    all_trailers = Trailers(res = "720", verbose = True)

..works, but then it claims "Ran 3 tests in 0.000s" which is incorrect.. The only other way I could think of is to have a cache_trailers global variable (which works correctly, but is rather horrible):

cache_trailers = None
class test_appletrailer(unittest.TestCase):
    def setUp(self):
        global cache_trailers
        if cache_trailers is None:
            cache_trailers = self.all_trailers = all_trailers = Trailers(res = "720", verbose = True)
        else:
            self.all_trailers = cache_trailers
+7  A: 

How about using a class member that only gets initialized once?

class test_appletrailer(unittest.TestCase):

    all_trailers = None

    def setup(self):
        # Only initialize all_trailers once.
        if self.all_trailers is None:
            self.__class__.all_trailers = Trailers(res = "720", verbose = True)

Lookups that refer to self.all_trailers will go to the next step in the MRO -- self.__class__.all_trailers, which will be initialized.

cdleary
+1  A: 

What is Trailers class doing?
If it holds some state, then you have to reset it each time unit test is being executed.

To solve your problem, I would use a mock object - just emulating the interface of Trailers, providing a faked set of data.


Update: as Trailers is only reading XML data, I would go for a solution like the one proposed by cdleary.

Roberto Liffredo
Trailers() retrieves and parsers an XML, it's read-only (so there's no saved state)
dbr
In that case, I would go for cdleary solution
Roberto Liffredo
+4  A: 

An alternative to the proposed solution would be to use a more featured test runner like Nose. With Nose, you can have module-level setup functions which will be run once for a test module. Since it is entirely compatible with unittest, you wouldn't have to change any code.

From the Nose manual:

nose supports fixtures at the package, module, class, and test case level, so expensive initialization can be done as infrequently as possible.

Fixtures are described in detail here. Of course, apart from fulfilling your use-case, I can also strongly recommend it as a general testing tool. None of my projects will leave home without it.

Ali A
Good point. I have to add Nose to the list of things to know/try in 2009 :-)
Roberto Liffredo
It will be 15 minutes well spent. Just try running "nosetests" in the root of any Python project as a starter. It will run your current tests without you changing anything.
Ali A