How to add apps to INSTALLED_APPS for tests?

Learn how to add apps to installed_apps for tests? with practical examples, diagrams, and best practices. Covers python, django development techniques with visual explanations.

Adding Apps to INSTALLED_APPS for Django Tests

Hero image for How to add apps to INSTALLED_APPS for tests?

Learn how to dynamically add Django apps to INSTALLED_APPS specifically for testing purposes, enabling isolated and efficient test environments without modifying production settings.

When developing Django applications, it's common to have specific apps that are only relevant during testing. These might include mock services, test utilities, or apps that provide fixtures. Directly adding these to your main INSTALLED_APPS in settings.py can clutter your production environment or introduce unnecessary dependencies. This article explores robust methods to dynamically include test-specific apps in INSTALLED_APPS only when running your test suite, ensuring a clean separation between development/production and testing configurations.

The Challenge: Test-Specific Apps

Django's INSTALLED_APPS setting is a crucial part of its configuration, defining which applications are active in a project. For testing, you might need to activate apps that provide:

  • Mocking capabilities: Apps that replace external services with test doubles.
  • Test utilities: Helper apps with custom test commands or base test classes.
  • Fixture providers: Apps that define models or data specifically for testing scenarios.

Including these in your main settings.py can lead to issues like increased startup time, unnecessary database migrations, or even security vulnerabilities if test-only apps are accidentally deployed to production. The goal is to activate them conditionally.

flowchart TD
    A[Start Test Run] --> B{Is `INSTALLED_APPS` Modified?}
    B -->|No| C[Load Default `INSTALLED_APPS`]
    B -->|Yes| D[Load Modified `INSTALLED_APPS`]
    C --> E[Run Tests]
    D --> E
    E --> F[End Test Run]

Flowchart illustrating conditional loading of INSTALLED_APPS during testing.

Method 1: Modifying settings.py Conditionally

One straightforward approach is to modify INSTALLED_APPS directly within your settings.py based on an environment variable or a specific test flag. This is often done by checking if the DJANGO_SETTINGS_MODULE environment variable indicates a test settings file, or by checking if sys.argv contains 'test'.

# myproject/settings.py

import sys

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'my_app',
    # ... other production apps
]

# Add test-specific apps only when running tests
if 'test' in sys.argv or 'pytest' in sys.argv:
    INSTALLED_APPS += [
        'my_test_app',
        'another_test_utility',
    ]

# Or, if using a separate test settings file:
# if 'DJANGO_SETTINGS_MODULE' in os.environ and 'test_settings' in os.environ['DJANGO_SETTINGS_MODULE']:
#     INSTALLED_APPS += [
#         'my_test_app',
#     ]

Method 2: Using a Custom Test Runner

For more advanced scenarios or when you need fine-grained control, creating a custom test runner is a powerful option. A custom test runner allows you to programmatically modify Django's settings before the test suite is initialized. This is particularly useful if you need to add apps that require specific setup or teardown logic.

# myproject/test_runner.py

from django.test.runner import DiscoverRunner
from django.conf import settings

class MyCustomTestRunner(DiscoverRunner):
    def setup_test_environment(self, **kwargs):
        # Add test-specific apps to INSTALLED_APPS
        settings.INSTALLED_APPS += [
            'my_test_app',
            'another_test_utility',
        ]
        # Ensure settings are reloaded if necessary (though usually not needed for INSTALLED_APPS)
        settings.configure(settings)
        super().setup_test_environment(**kwargs)

    def teardown_test_environment(self, **kwargs):
        # Clean up if necessary (e.g., remove test apps, though not strictly required for INSTALLED_APPS)
        super().teardown_test_environment(**kwargs)

# In myproject/settings.py, set:
# TEST_RUNNER = 'myproject.test_runner.MyCustomTestRunner'

After creating myproject/test_runner.py, you need to configure Django to use it by adding TEST_RUNNER = 'myproject.test_runner.MyCustomTestRunner' to your settings.py.

Method 3: Separate Test Settings File

The most common and often recommended approach for managing test-specific configurations is to use a completely separate settings file for your test environment. This provides a clean separation and allows you to override any setting for tests without affecting your development or production configurations.

1. Create a test_settings.py file

Inside your project's settings directory (e.g., myproject/myproject/), create a new file named test_settings.py.

2. Import base settings

In test_settings.py, import all settings from your base settings.py file.

3. Override INSTALLED_APPS

Modify INSTALLED_APPS in test_settings.py to include your test-specific apps. You can either append to the existing list or define a completely new list.

4. Run tests with the new settings

Execute your tests using the DJANGO_SETTINGS_MODULE environment variable to point to your test_settings.py.

# myproject/myproject/test_settings.py

from .settings import *

# Override or extend INSTALLED_APPS for testing
INSTALLED_APPS += [
    'my_test_app',
    'another_test_utility',
]

# You can also override other settings specific to tests, e.g.:
# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': ':memory:',
#     }
# }

# DEBUG = False # Often set to False for tests
DJANGO_SETTINGS_MODULE=myproject.test_settings python manage.py test