[TIP] setUp and tearDown behavior

holger krekel holger at merlinux.eu
Tue Jan 19 06:55:18 PST 2010


Hi Alfredo,

On Mon, Jan 18, 2010 at 21:37 -0500, Alfredo Deza wrote:
> I am building some tests for a Python installer that copies some files and
> changes some permissions.
> 
> Nothing weird there.
> 
> However, in the test class I am starting with a setUp that basically calls
> the installer (so the tests can see if everything is where it should be),
> this is followed by a few assertions and finally a tearDown is called where
> everything gets uninstalled.
> 
> When running the tests with nosetests, I see that setUp and tearDown are
> called for *every* method in my test class (e.g. installs => runs test
> method => uninstalls ....)
> 
> Isn't setUp supposed to be run once at the beginning of the class? or is
> this expected?
> 
> In case this is expected, is there a way to do it *just once *for all the
> methods?

The others gave various answers related to unittest and its extensions - 
i'd like to add another way using py.test "funcargs".  The main advantage 
is that you can completely decouple test fixture and actual test code, allowing
for more flexibility and ease of doing functional/system testing.  

Example: you write one or multiple test functions that look like this 
(also can be put on a class of course):

    def test_installer(setupdir):
        # do your tests, setupdir is your fixture state

This is a test function that runs and works with a "setupdir" function argument.
You define a function argument factory which is invoked to provide 
an instance of it: 

    def pytest_funcarg__setupdir(request):   
        return request.cached_setup(scope="session", 
            setup=lambda: MySetupDir(), 
            teardown=lambda mysetupdir: mysetupdir.finish()
        )

The specified 'setup' and 'teardown' will be called exactly once per 
session.  If you don't run a test that needs the funcarg the factory
function will not be called at all.  In any case, your test functions 
can stay completely ignorant from how fixtures are managed. 

You can change scoping by modifying the factory function - e.g. 
add a command line option that forces "function" scoping which usually
avoids "cascading failures" and provides better test isolation at the expensve
of longer test run durations.  Useful for a nightly Continous Integration
configuration. 

Lastly, the 'request' object is a handle to the particular test
function - it provides access to the test function object, its module, 
class object etc. and you can thus easily mark a test to receive a 
specially parametrized "setupdir" ...  see http://tinyurl.com/yfw82l5 
for details. 

cheers,
holger



More information about the testing-in-python mailing list