15
votes

I want to have a "global fixture" (in pytest they could also be called "session scoped fixtures") which does some expensive environment setup, like typically preparing a resource, which is then reused across test modules. The setup is something like this,

shared_env.py

would have a fixture doing something expensive, like starting up a Docker container, MySQL server, etc.

@pytest.yield_fixture(scope="session")
def test_server():
    start_docker_container(port=TEST_PORT)
    yield TEST_PORT
    stop_docker_container()

test_a.py

would use the server,

def test_foo(test_server): ...

test_b.py

would use the same server

def test_foo(test_server): ...

It seems that pytest has support for this via scope="session", but I can't figure out how to make the actual imports work. The current setup will given an error message like,

fixture 'test_server' not found
available fixtures: pytestconfig, ...
use 'py.test --fixtures [testpath] ' for help on them
2

2 Answers

21
votes

There is a convention in pytest which uses the special file named conftest.py and contains session fixtures.

I have extracted two very simple examples to give a quick start. They do not use classes.

Everything taken from http://pythontesting.net/framework/pytest/pytest-session-scoped-fixtures/

Example 1:

The fixture is not executed unless supplied as an argument to a test_* function. The fixture some_resource is executed prior to calling the referencing function, in this case test_2. The finalizer on the other hand is executed at the end.

conftest.py:

import pytest
@pytest.fixture(scope="session")

def some_resource(request):
  print('\nSome resource')
 
  def some_resource_fin():
    print('\nSome resource fin')

  request.addfinalizer(some_resource_fin)

test_a.py:

def test_1():
  print('\n Test 1')
 
def test_2(some_resource):
  print('\n Test 2')

def test_3():
  print('\n Test 3')

Result:

$ pytest -s
======================================================= test session starts ========================================================
platform linux -- Python 3.4.3 -- py-1.4.26 -- pytest-2.7.0
rootdir: /tmp/d2, inifile: 
collected 3 items 

test_a.py 
 Test 1
.
Some recource

 Test 2
.
 Test 3
.
Some resource fin

Example 2:

Here the fixture is configured with autouse=True, so it is executed once at the beginning of the session, and it does not have to be referenced. Its finalizer is executed at the end of the session.

conftest.py:

import pytest
@pytest.fixture(scope="session", autouse=True)

def auto_resource(request):
  print('\nSome resource')
 
  def auto_resource_fin():
    print('\nSome resource fin')

  request.addfinalizer(auto_resource_fin)

test_a.py:

def test_1():
  print('\n Test 1')
 
def test_2():
  print('\n Test 2')

def test_3():
  print('\n Test 3')

Result:

$ pytest -s
======================================================= test session starts ========================================================
platform linux -- Python 3.4.3 -- py-1.4.26 -- pytest-2.7.0
rootdir: /tmp/d2, inifile: 
collected 3 items 

test_a.py 
Some recource

 Test 1
.
 Test 2
.
 Test 3
.
Some resource fin
4
votes

Okay, I think I got it ... the solution is to name shared_env.py conftest.py

See this good blog post for details [ http://pythontesting.net/framework/pytest/pytest-session-scoped-fixtures/ ]. It has a working example, so hopefully not too hard to work backwards from there if necessary.