39

I have a bunch of tests written using pytest. There are all under a directory dir. For example:

dir/test_base.py
dir/test_something.py
dir/test_something2.py
...

The simplified version of code in them is as follows:

test_base.py

import pytest

class TestBase:
   def setup_module(module):
      assert False

   def teardown_module(module):
      assert False

test_something.py

import pytest
from test_base import TestBase

class TestSomething(TestBase):
   def test_dummy():
       pass

test_something2.py

import pytest
from test_base import TestBase

class TestSomethingElse(TestBase):
   def test_dummy2():
       pass

All my test_something*.py files extend the base class in test_base.py. Now I wrote setup_module(module) and teardown_module(module) methods in test_base.py. I was expecting the setup_module to be called once for all tests, and teardown_module() to be called at the end, once all tests are finished.

But the functions don’t seem to be getting called? Do I need some decorators for this to work?

bsplosion
  • 2,641
  • 27
  • 38
vinodkone
  • 2,731
  • 4
  • 22
  • 21

4 Answers4

22

The OP's requirement was for setup and teardown each to execute only once, not one time per module. This can be accomplished with a combination of a conftest.py file, @pytest.fixture(scope="session") and passing the fixture name to each test function.

These are described in the Pytest fixtures documentation

Here's an example:

conftest.py

import pytest

@pytest.fixture(scope="session")
    def my_setup(request):
        print '\nDoing setup'
        def fin():
            print ("\nDoing teardown")
        request.addfinalizer(fin)

test_something.py

def test_dummy(my_setup):
    print '\ntest_dummy'

test_something2.py

def test_dummy2(my_setup):
    print '\ntest_dummy2'

def test_dummy3(my_setup):
    print '\ntest_dummy3'

The output when you run py.test -s:

collected 3 items 

test_something.py 
Doing setup

test_dummy
.
test_something2.py 
test_dummy2
.
test_dummy3
.
Doing teardown

The name conftest.py matters: you can't give this file a different name and expect Pytest to find it as a source of fixtures.

Setting scope="session" is important. Otherwise setup and teardown will be repeated for each test module.

If you'd prefer not to pass the fixture name my_setup as an argument to each test function, you can place test functions inside a class and apply the pytest.mark.usefixtures decorator to the class.

Nimrand
  • 1,748
  • 2
  • 16
  • 29
Steve Saporta
  • 4,581
  • 3
  • 30
  • 32
15

Put setup_module and teardown_module outside of a class on module level. Then add your class with your tests.

def setup_module(module):
    """..."""

def teardown_module(module):
    """..."""

class TestSomething:

    def test_dummy(self):
        """do some tests"""

For more info refer to this article.

Jabba
  • 19,598
  • 6
  • 52
  • 45
1

setup_module/teardown_module are called for the module where the eventual (derived) tests are defined. This also allows to customize the setup. If you only ever have one setup_module you can put it to test_base.py and import it from the other places. HTH.

hpk42
  • 21,501
  • 4
  • 47
  • 53
-1

First of all it is a good practice to put all tests in a module called "tests":

<product>
   ...
   tests/
      __init__.py
      test_something.py

Secondly I think you should use setup_class/teardown_class methods in your base class:

import unittest
class MyBase(unittest.TestCase):

   @classmethod
   def setup_class(cls):
       ...

   @classmethod
   def teardown_class(cls):
       ...

More info: http://pytest.org/latest/xunit_setup.html

Giacomo Spettoli
  • 4,476
  • 1
  • 16
  • 24
  • Is there a reason this answer doesn't address specifically his trouble using the document-defined **Module level setup/teardown**. Are you suggesting the `setup_module(module)` / `teardown_module(module)` functions do not work as documented? – jdi Oct 16 '11 at 20:29
  • 2
    Im just asking if you are implying that those documented methods do not work, as suggested by your answer to do it in the __init__ instead. Thats all. Because even in your link, you reference to the doc that explains to use those methods, which are broken for the OP – jdi Oct 16 '11 at 22:06
  • Hi @GiacomoSpettoli thanks for your reply. I am actually looking for getting setup_module/teardown_module to work, instead of setup_class/teardown_class. Because, I want these to be invoked only once for all tests. setup_class/teardown_class will be called for each of my tests that derive my base class. HTH – vinodkone Oct 18 '11 at 18:43
  • 1
    I see...so you should try to put those methods in the __ init __.py. That was my first answer but I changed it because, without your last constraint, the use of class methods looked cleaner. – Giacomo Spettoli Oct 18 '11 at 19:03