简体   繁体   中英

Testing methods each with a different setup/teardown

I'm testing a class, with many test methods. However, each method has a unique context. I then write my code as following:

class TestSomeClass(unittest.TestCase):
    def test_a():
        with a_context() as c:
            pass

    def test_b():
        with b_context() as c:
            pass

    def test_c():
        with c_context() as c:
            pass

However, the context managers are irrelevant to the test case, and produce temporary files. So as to not pollute the file system when the test fails, I would like to use each context manager in a setup/teardown scenario.

I've looked at nose's with_setup , but the docs say that is meant for functions only, not methods. Another way is to move the test methods to separate classes each with a setup/teardown function. What's a good way to do this?

First of all, I'm not sure why what you have isn't working. I wrote some test code, and it shows that the exit code always gets called, under the unittest.main() execution environment. (Note, I did not test nose, so maybe that's why I couldn't replicate your failure.) Maybe your context manager is broken?

Here's my test:

import unittest
import contextlib
import sys

@contextlib.contextmanager
def context_mgr():
    print "setting up context"
    try:
        yield
    finally:
        print "tearing down context"

class TestSomeClass(unittest.TestCase):
    def test_normal(self):
        with context_mgr() as c:
            print "normal task"

    def test_raise(self):
        with context_mgr() as c:
            print "raise task"
            raise RuntimeError

    def test_exit(self):
        with context_mgr() as c:
            print "exit task"
            sys.exit(1)

if __name__ == '__main__':
    unittest.main()

By running that with $ python test_test.py I see tearing down context for all 3 tests.

Anyway, to answer your question, if you want a separate setup and teardown for each test, then you need to put each test in its own class. You can set up a parent class to do most of the work for you, so there isn't too much extra boilerplate:

class TestClassParent(unittest.TestCase):
    context_guard = context_mgr()
    def setUp(self):
        #do common setup tasks here
        self.c = self.context_guard.__enter__()
    def tearDown(self):
        #do common teardown tasks here
        self.context_guard.__exit__(None,None,None)

class TestA(TestClassParent):
    context_guard = context_mgr('A')
    def test_normal(self):
        print "task A"

class TestB(TestClassParent):
    context_guard = context_mgr('B')
    def test_normal(self):
        print "task B"

This produces the output:

$ python test_test.py 
setting up context: A
task A
tearing down context: A
.setting up context: B
task B
tearing down context: B
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM