I am having a hard time writing some tests for an application. Basically I have an autouse fixture in conftest.py that sets up some environment variables that the application needs to initialize some objects:
# conftest.py
@pytest.fixture(autouse=True)
def env_config(monkeypatch):
monkeypatch.setenv('ACCESS_KEY_ID', '12313221323')
monkeypatch.setenv('SECRET_ACCESS_KEY', '12313221323')
monkeypatch.setenv('REGION', '12313221323')
# ...
The problem is that this fixture is only run until _each_ test starts. However, in a specific test file, I am importing the module that contains functions I want to test, _outside_ the tests:
# test_my_func.py
import app
class TestMyFunc:
def test_foo_(self):
# Test something about app.foo
pass
Importing app crashes because the environment variables are not set _yet_:
# app.py
from requests_aws4auth import AWS4Auth
awsauth = AWS4Auth(
ACCESS_KEY_ID,
SECRET_ACCESS_KEY,
REGION,
'es'
)
def foo():
pass
I cannot use a blank string as a fallback for os.getenv since AWS4Auth fails when using them.
If I move import app inside the test, everything works perfectly since the autouse fixture has already been executed.
Would appreciate some advice.
GitMate.io thinks possibly related issues are https://github.com/pytest-dev/pytest/issues/1050 (provide dependency-tested autouse fixtures), https://github.com/pytest-dev/pytest/issues/2861 (Question re: order of execution of test fixtures), https://github.com/pytest-dev/pytest/issues/668 (autouse fixtures break scope rules), https://github.com/pytest-dev/pytest/issues/2992 (Already imported module), and https://github.com/pytest-dev/pytest/issues/1057 (Pytest fail when autouse fixture is applied and --doctest-modules is set).
Hi @BigChief45,
One approach is changing your application to a fixture, specially if it provides functionality that your tests need (login, endpoints, etc). This fixture should then depend on env_config, which will make env_config execute first.
# conftest.py
import pytest
@pytest.fixture
def app(env_config):
import app
return app.App()
If your app.py just initializes some globals and doesn't provide any functionality, then one way would be to move the initialization code from import time to a function:
# app.py
from requests_aws4auth import AWS4Auth
def startup():
awsauth = AWS4Auth(
ACCESS_KEY_ID,
SECRET_ACCESS_KEY,
REGION,
'es'
)
def foo():
pass
This way you have more control when setup gets called, so you can move the setup call into the env_config fixture after monkeypatching the environment vars (which probably should be renamed to something more appropriate like app_setup). Of course, your actual "main" entry point now needs to call setup explicitly instead of just importing app, but I believe this is for the best as it is usually recommended to do too much stuff at import time.
Hope this helps!
You may also find pytest-env useful. Here's an example where I've used it. It'll set up these environment variables before your test suite is imported
@nicoddemus Thanks for the suggestion. This approach works very well!
@asottile Looks nice, I'll be sure to try it thanks!
Closing issue.
Most helpful comment
You may also find pytest-env useful. Here's an example where I've used it. It'll set up these environment variables before your test suite is imported