How to add apps to INSTALLED_APPS for tests?
Categories:
Adding Apps to INSTALLED_APPS for Django 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',
# ]
sys.argv
is simple, it's generally more robust to use environment variables or a dedicated test settings file for more complex test configurations. This avoids coupling your settings directly to the command-line arguments of the test runner.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
.
settings
directly within a test runner, be mindful of the order of operations. setup_test_environment
is called early in the test process, making it suitable for INSTALLED_APPS
modifications. However, modifying other settings might require more careful consideration of when they are accessed by Django.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
test_settings.py
is generally the cleanest and most maintainable approach, especially for larger projects. It keeps your test configuration entirely isolated from your development and production settings, reducing the risk of unintended side effects.