[Python] How to handle differently scope fixtures that share a single "session" scoped fixture?

Discussão em 'Python' iniciado por Stack, Julho 10, 2025.

  1. Stack

    Stack Membro Participativo

    It's common to have some resource that can be expensive to spin up in tests and so you want to scope it to "session". You can then have a function scoped fixture to "reset" the shared resource, you can even include some defaults. Something like:

    import pytest

    @pytest.fixture(scope="session")
    def some_resource():
    resource = []
    yield resource
    # Delete the resource

    @pytest.fixture(scope="function")
    def resource_function_scoped(some_resource):
    # Clean the resource and add in some defaults
    some_resource.clear()
    some_resource.append("function_scoped_default")
    yield some_resource
    # Clean up the resource after the test
    some_resource.clear()


    I was using something like this but for a bunch of my tests the clean up and defaulting is becoming very expensive. This means I want to move it higher up the scope. Something like:

    import pytest

    @pytest.fixture(scope="session")
    def some_resource():
    resource = []
    yield resource
    # Delete the resource

    @pytest.fixture(scope="function")
    def resource_function_scoped(some_resource):
    # Clean the resource and add in some defaults
    some_resource.clear()
    some_resource.append("function_scoped_default")
    yield some_resource
    # Clean up the resource after the test
    some_resource.clear()

    @pytest.fixture(scope="class")
    def resource_class_scoped(some_resource):
    # Clean the resource and add in some defaults
    some_resource.clear()
    some_resource.append("class_scoped_default")
    yield some_resource
    # Clean up the resource after the test
    some_resource.clear()


    However, there's now a danger that the two differently-scoped fixtures clash. If you use the above fixtures and run the following test then you'll get a failure that would be very difficult to diagnose:

    class TestFunctionScope:
    def test_function_scope(self, resource_function_scoped):
    assert resource_function_scoped == ["function_scoped_default"]

    class TestClassScope:
    def test_class_scope(self, resource_class_scoped):
    assert resource_class_scoped == ["class_scoped_default"]

    class TestBoth:
    def test_class_scope(self, resource_class_scoped):
    assert resource_class_scoped == ["class_scoped_default"]
    def test_function_scope(self, resource_function_scoped):
    assert resource_function_scoped == ["function_scoped_default"]
    def test_class_scope_again(self, resource_class_scoped):
    # Fails with assert [] == ['class_scoped_default']
    assert resource_class_scoped == ["class_scoped_default"]


    So there's two solutions I see to this, but I don't know how to achieve either of them:

    1. Tell pytest that the fixtures resource_function_scoped and resource_class_scoped aren't compatible and that if a new test requires one or the other it needs to teardown the other?
    2. Add in some asserts that make diagnosing the above failures much easier. This way poorly written tests can still occur but it's at least obvious what you need to change to fix them.

    How could I achieve either of the above?

    Continue reading...

Compartilhe esta Página