2
votes

I'm building a pytest test suite, testing a package I'm building. The tests should verify some things about the pkg, such as minor functionality checks, minor sanity checks and so on. Some of the checks are done pre-install and some post-install (example code):


Tests file:

import pytest

class PreInstallTests(object):
    def test_foo(self, bar):
        assert bar > 2

class PostInstallTests(object):
    def test_goo(self, baz):
        assert baz < 3

    def test_hoo(self, baz):
        assert baz > 1

conftest file:

import pytest
@pytest.fixture
def tmp_dir():
    os.mkdir('tmp')
    yield
    shutil.rmtree('tmp')

@pytest.fixture
def bar(tmp_dir):
    yield 3

@pytest.fixture
def baz(install, tmp_dir):
    yield 2

@pytest.fixture(scope='session')
def install():
    # installs the pkg... (takes a lot of time)

As can be seen here, I have 2 post-install tests, each one using a fixture called baz that uses the install fixture. I want to have only one installation, and either use the same installation for all post-install-tests (not ideal, but the tests are minimal, and I don't want to waste much time on re-installing currently).

Using the "scope" session parameter can solve my problem, but that would prohibit me from using any other fixture, such as "tmp_dir" (which represents a fixture that I need, and must stay default-scoped...)

How can I achieve one install for all tests, and still use my other fixtures, whom I want to leave with their default scope?

I thought of making the install an autouse fixture, but I actually need it to be called after some of the other fixtures that are currently default scoped, and should stay that way

2
Using the "scope" session parameter can solve my problem, but that would prohibit me from using any other fixture, such as "tmp_dir" - you mean, prohibit using tmp_dir in install? Other than that (and wrong placed scope parameter in the install fixture), I don't see any issues with your code. - hoefling
You can always introduce another fixture, like e.g. real_install which is session-scoped, and change install to smth like def install(tmp_dir, real_install): return real_install with the default function scope. This way, the installation will still run once and you can combine its result with function-scoped fixtures. - hoefling
@hoefling For your 1st comment - yes, but I actually have a lot of fixtures like that one.. For your 2nd - thought about it, but that would make me change a lot of my fixtures into function calls (e.g. I have a fixture that shows the path of the pkg - so that would have to be a call to function) - CIsForCookies
@CIsForCookies, do you mean to say you want to use tmp_dir and many such function scoped fixtures in install fixture? Or you just want them be called before the install fixture. - yeniv

2 Answers

1
votes

Only solution I could think of is to have a flag controlling if you've already run the installation code, then keep the fixture with default scope.


import pytest

installed = False

@pytest.fixture()
def install():
    global installed
    if not installed:
        print('installing')
        installed = True
0
votes

as described in ScopeMismatch on using session scoped fixture with pytest-mozwebqa plugin for py.test

use the session scoped tmpdir_factory for install and remove tmp_dir, consume builtin tmpdir, since pytest 3.x.