pytest-django icon indicating copy to clipboard operation
pytest-django copied to clipboard

Non-global for multiple values for DJANGO_SETTINGS_MODULE? How?

Open posita opened this issue 3 years ago • 0 comments
trafficstars

I am dealing with a fairly complicated mono-repo that defines multiple Django instances in subdirectories. Something like this:

.
├── src/
│   ├── django_instance1/
│   │   ├── app1/
│   │   │   ├── apps.py
│   │   │   ├── __init__.py
│   │   │   ├── models.py
│   │   │   ├── schema.py
│   │   │   └── views.py
│   │   ├── asgi.py
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── django_instance2/
│   │   ├── app2/
│   │   │   ├── apps.py
│   │   │   ├── __init__.py
│   │   │   ├── models.py
│   │   │   ├── schema.py
│   │   │   └── views.py
│   │   ├── asgi.py
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   └── __init__.py
└── tests/
    ├── django_instance1_tests/
    │   ├── ...
    │   ├── conftest.py
    │   └── __init__.py
    └── django_instance2_tests/
        ├── ...
        ├── conftest.py
        └── __init__.py

For reasons beyond the scope of this issue, I need to test each with different DJANGO_SETTINGS_MODULEs (e.g,. DJANGO_SETTINGS_MODULE=django_instance1.settings for tests/django_instance1_tests, DJANGO_SETTINGS_MODULE=django_instance2.settings for tests/django_instance2_tests, etc.).

How do I do this? It seems like pytest and pytest-django want one global value for DJANGO_SETTINGS_MODULE to be set at collection time.

I tried using conftest.py for each Django instance as follows:

# tests/django_instance1_tests/conftest.py
from __future__ import annotations
import pytest

@pytest.fixture(autouse=True)
def env_setup(monkeypatch):
    monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "django_instance1.settings")

This doesn't really work, though. Say I have a test (e.g., in tests/django_instance1_tests/test_foo.py):

from __future__ import annotations

def test_foo(settings, client) -> None:
    import os
    assert os.environ.get("DJANGO_SETTINGS_MODULE") == "django_instance1.settings"  # yup
    assert settings.DATABASES  # works
    client.get("...")  # doesn't raise any exception

test_foo will pass, but I will get an exception like AttributeError: module 'django.core.mail' has no attribute 'outbox' on tests that are run after it.

If I use the db fixture or decorate test_foo with @pytest.mark.django_db, it will be skipped with the message no Django settings.

How do I accomplish what I need under these circumstances?

posita avatar Apr 09 '22 01:04 posita