Set a variable based on a py.test (testinfra) check output

I am trying to make a testinfra test file more portable, I'd like to use a single file to handle tests for either a prod / dev or test env. For this I need to get a value from the remote tested machine, which I get by :

def test_ACD_GRAIN(host):
    grain = host.salt("grains.item", "client_NAME")
    assert grain['client_NAME'] == "test"

I'd need to use this grain['client_NAME'] value in different part of the test file, therefore I'd like to store it in a variable.

Anyway to do this ?

Answers

There are a lot of ways to share state between tests. To name a few:

Using a session-scoped fixture

Define a fixture with a session scope where the value is calculated. It will executed before the first test that uses it runs and then will be cached for the whole test run:

# conftest.py
@pytest.fixture(scope='session')
def grain():
    host = ...
    return host.salt("grains.item", "client_NAME")

Just use the fixture as the input argument in tests to access the value:

def test_ACD_GRAIN(grain):
    assert grain['client_NAME'] == "test"

Using pytest namespace

Define an autouse fixture with a session scope, so it is autoapplied once per session and stores the value in the pytest namespace.

# conftest.py

import pytest


def pytest_namespace():
    return {'grain': None}


@pytest.fixture(scope='session', autouse=True)
def grain():
    host = ...
    pytest.grain = host.salt("grains.item", "client_NAME")

It will be executed before the first test runs. In tests, just call pytest.grain to get the value:

import pytest

def test_ACD_GRAIN():
    grain = pytest.grain
    assert grain['client_NAME'] == "test"

pytest cache: reuse values between test runs

If the value does not change between test runs, you can even persist in on disk:

@pytest.fixture
def grain(request):
    grain = request.config.cache.get('grain', None)
    if not grain:
        host = ...
        grain = host.salt("grains.item", "client_NAME")
        request.config.cache.set('grain', grain)
    return grain

Now the tests won't need to recalculate the value on different test runs unless you clear the cache on disk:

$ pytest
...
$ pytest --cache-show
...
grain contains:
  'spam'

Rerun the tests with the --cache-clear flag to delete the cache and force the value to be recalculated.

Posted on by hoefling

Relevant tags