python unittests with multiple setups?

Question:

I’m working on a module using sockets with hundreds of test cases. Which is nice. Except now I need to test all of the cases with and without socket.setdefaulttimeout( 60 )… Please don’t tell me cut and paste all the tests and set/remove a default timeout in setup/teardown.

Honestly, I get that having each test case laid out on it’s own is good practice, but i also don’t like to repeat myself. This is really just testing in a different context not different tests.

i see that unittest supports module level setup/teardown fixtures, but it isn’t obvious to me how to convert my one test module into testing itself twice with two different setups.

any help would be much appreciated.

Asked By: underrun

||

Answers:

I would do it like this:

  1. Make all of your tests derive from your own TestCase class, let’s call it SynapticTestCase.

  2. In SynapticTestCase.setUp(), examine an environment variable to determine whether to set the socket timeout or not.

  3. Run your entire test suite twice, once with the environment variable set one way, then again with it set the other way.

  4. Write a small shell script to invoke the test suite both ways.

Answered By: Ned Batchelder

If your code does not call socket.setdefaulttimeout then you can run tests the following way:

import socket
socket.setdeaulttimeout(60)
old_setdefaulttimeout, socket.setdefaulttimeout = socket.setdefaulttimeout, None
unittest.main()
socket.setdefaulttimeout = old_setdefaulttimeout

It is a hack, but it can work

Answered By: Alexandr Priymak

The other answers on this question are valid in as much as they make it possible to actually perform the tests under multiple environments, but in playing around with the options I think I like a more self contained approach. I’m using suites and results to organize and display results of tests. In order to run one tests with two environments rather than two tests I took this approach – create a TestSuite subclass.

class FixtureSuite(unittest.TestSuite):
    def run(self, result, debug=False):
        socket.setdefaulttimeout(30)
        super().run(result, debug)
        socket.setdefaulttimeout(None)
...
suite1 = unittest.TestSuite(testCases)
suite2 = FixtureSuite(testCases)
fullSuite = unittest.TestSuite([suite1,suite2])
unittest.TextTestRunner(verbosity=2).run(fullSuite)
Answered By: underrun

you could do something like this:

class TestCommon(unittest.TestCase):
    def method_one(self):
        # code for your first test
        pass

    def method_two(self):
        # code for your second test
        pass

class TestWithSetupA(TestCommon):
    def SetUp(self):
        # setup for context A
        do_setup_a_stuff()

    def test_method_one(self):
        self.method_one()

    def test_method_two(self):
        self.method_two()

class TestWithSetupB(TestCommon):
    def SetUp(self):
        # setup for context B
        do_setup_b_stuff()

    def test_method_one(self):
        self.method_one()

    def test_method_two(self):
        self.method_two()
Answered By: Bazyli Debowski

You could also inherit and rerun the original suite, but overwrite the whole setUp or a part of it:

class TestOriginal(TestCommon):
    def SetUp(self):
        # common setUp here

        self.current_setUp()

    def current_setUp(self):
        # your first setUp
        pass

    def test_one(self):
        # your test
        pass

    def test_two(self):
        # another test
        pass

class TestWithNewSetup(TestOriginal):
    def current_setUp(self):
        # overwrite your first current_setUp
Answered By: a regular fellow

And what if I need opposite functionality – one Setup for multiple TestCase-modules? Create a separate module with Basic Class within setupClass and just inherit from it in all testcase-modules? Pls advise.

Answered By: ruslanway