Search code examples
pythonpython-3.xpytest

Configure pytest fixtures


I want to configure fixtures in pytest. Specifically, I am trying to test a keyring application. I'm passing a keyring service name to a custom store (I build myself) and after the test, I want to delete those passwords.

So I build a basic fixture:

import keyring

@pytest.fixture()
def keyring_test_service_name() -> str:
    """
    A service name for testing the keyring store. Never use the default service name in tests, because it might
    overwrite the production credentials.
    This fixture also deletes the stored credentials after the test.
    """
    name = "my-service-name-test"
    yield name
    
    # Do the cleanup
    keyring.delete_password(name, "id")
    keyring.delete_password(name, "secret")

Now, after some testwriting, I figured that I do not always need that cleanup. It raised an error because I have never set that credential. So I wanted to add a bool cleanup to my fixture, which controls if I want to do that cleanup.

I am imagining something like this:

@pytest.fixture()
def keyring_test_service_name() -> str:
    """
    A service name for testing the keyring store. Never use the default service name in tests, because it might
    overwrite the production credentials.
    This fixture also deletes the stored credentials after the test.
    """
    cleanup = True  # Retrieve the configuration here
    name = "my-service-name-test"
    yield name
    if cleanup:
        keyring.delete_password(name, "id")
        keyring.delete_password(name, "secret")

How do I configure that fixture from outside (when I'm writing the tests) so I can control when I do the cleanup and when I should not? How do I provide a default value, so I dont have to change my old tests?

I appreciate your help!


Solution

  • You can use marker to send boolean from your test to fixture.

    @pytest.fixture()
    def keyring_test_service_name(request) -> str:
        """
        A service name for testing the keyring store. Never use the default service name in tests, because it might
        overwrite the production credentials.
        This fixture also deletes the stored credentials after the test.
        """
        cleanup = request.node.get_closest_marker("clean_up")
    
        name = "my-service-name-test"
        yield name
    
        if cleanup is not None and cleanup.args[0] == True:
          
            keyring.delete_password(name, "id")
            keyring.delete_password(name, "secret")
    
    @pytest.mark.clean_up(True)
    def test_something(keyring_test_service_name):
    

    to avoid warning about custom marker, you can add your marker in pytest.ini

    pytest.ini

    markers =
    
        clean_up: A flag to handle tear_down