Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doctests appear to run before session scope fixtures #768

Closed
pytestbot opened this issue Jun 14, 2015 · 9 comments
Closed

doctests appear to run before session scope fixtures #768

pytestbot opened this issue Jun 14, 2015 · 9 comments

Comments

@pytestbot
Copy link
Contributor

Originally reported by: Jason R. Coombs (BitBucket: jaraco, GitHub: jaraco)


I've created a session scoped fixture in ./conftest.py:

@pytest.fixture(autouse=True, scope='session')
def myfixture():
  raise ValueError()

Then, I create a module to be doctested:

def foo():
  """
  >>> assert True
  """

Then, I run pytest with --doctest-modules.

It completes one test on "mod.py" and it passes. Furthermore, if anything in the session scope is required by the doctest, it won't yet be setup. It seems that doctests are run outside of the test session.

I understand that session scope fixtures are meant to serve as test setup and teardown. However, they seem not to be available for doctests.

Is there any way to set up the context for doctests? I'd like to incorporate another fixture from a plugin during setup as well.


@pytestbot pytestbot added the task label Jun 15, 2015
@nicoddemus
Copy link
Member

Hi @jaraco,

There's a common misunderstanding regarding session fixtures: they are not created at the beginning of the session but only when the first test which uses it executes. For example:

import pytest

@pytest.yield_fixture(scope='session')
def fix():
    print('fix created')
    yield 1
    print('fix destroyed')


def test_1(): pass
def test_2(): pass
def test_3(fix): pass
def test_4(): pass
def test_5(fix): pass
def test_6(): pass
def test_7(): pass

Executing it:

test_foo.py::test_1 PASSED
test_foo.py::test_2 PASSED
test_foo.py::test_3 fix created
PASSED
test_foo.py::test_4 PASSED
test_foo.py::test_5 PASSED
test_foo.py::test_6 PASSED
test_foo.py::test_7 PASSEDfix destroyed

This is intentional to avoid creating session fixtures which won't even be used during the test run (for example, executing py.test -k test_1 will prevent creating the fixture altogether).

Furthermore, fixtures in general are only available for python test functions... extending fixtures to other types of test functions might be tricky.

One workaround is to initialize your fixture in the pytest_configure hook. For example, suppose your session fixture looks like this:

# contents of conftest.py
import pytest
@pytest.yield_fixture(scope='session')
def session_data():
    data = MySessionData() # setup some global state
    yield data
    data.Close()

To make sure MySessionData is initialized even for doc tests while still have it available for python tests as usual, you can change it like this:

# contents of conftest.py

def pytest_configure(config):
    config.my_session_data = MySessionData() # setup some global state

def pytest_unconfigure(config):
    config.my_session_data.Close()

@pytest.fixture(scope='session')
def session_data(request):
    return request.config.my_session_data

Not ideal of course, but should work.

Hope this helps!
Cheers 🍻

@RonnyPfannschmidt
Copy link
Member

i suspect the underlying problem is different,

this is a autouse fixture, but doctests are not integrated with the fixture mechanism

so running a doctest first means the autouse fixture wont trigger, and the test will be unhappy

@nicoddemus
Copy link
Member

this is a autouse fixture, but doctests are not integrated with the fixture mechanism

Yep, I noticed it as well, but I assumed the fixture mechanism only worked with python functions, so it doesn't seem a problem with doctests specifically, but with fixtures in general.

@jaraco
Copy link
Contributor

jaraco commented Jul 12, 2015

I don't expect doctests to be integrated with the fixtures mechanism, but I would expect to be able to use the fixtures mechanism for its prescribed purpose (setup and teardown). I'm not able to use the pytest_configure hack because the global state I want to initialize is initialized from a session-scoped fixture in a plugin. In other words, I don't have access to that global state until the fixtures have been initialized.

Is there any reason that doctests should not be run after any autouse session fixtures are initialized? Alternately, is there a way that a session scoped fixture could be explicitly initialized in a pytest_configure operation (while still maintaining the guarantees of fixture setup and teardown)?

@nicoddemus
Copy link
Member

I'm not sure @jaraco, perhaps others can provide some insight here.

I will take a look at the code and see how hard it is to make autouse session-scoped fixtures to initialize before doctests, or see if I can find a workaround.

@RonnyPfannschmidt
Copy link
Member

as far as i can tell on master there is a integration of doctests and fixures,
im not sure if its also in the last release or if there is a subtle bug wrt scoping vs conf test locations

@nicoddemus
Copy link
Member

Seems related to #275.

@nicoddemus
Copy link
Member

In the end it was a bug! 😅

Thanks for reporting this @jaraco!

nicoddemus added a commit to nicoddemus/pytest that referenced this issue Jul 13, 2015
@jaraco
Copy link
Contributor

jaraco commented Jul 14, 2015

Awesome! Thanks everyone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants