Skip to content

Instantly share code, notes, and snippets.

@coredumperror
Last active August 4, 2017 00:14
Show Gist options
  • Save coredumperror/76747f42e8e97ecea76e0feb5983a953 to your computer and use it in GitHub Desktop.
Save coredumperror/76747f42e8e97ecea76e0feb5983a953 to your computer and use it in GitHub Desktop.
Use file storage on the local filesystem in Django unit tests
import shutil
import tempfile
from django.apps import apps
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.db.models import FileField
from django.db.models.loading import get_model, get_models
from django.test.runner import DiscoverRunner
class LocalStorageDiscoverRunner(DiscoverRunner):
"""
Use file storage on the local filesystem in unit tests.
Inspiration: https://www.caktusgroup.com/blog/2013/06/26/media-root-and-django-tests/
"""
def setup_test_environment(self):
super(TempMediaDiscoverRunner, self).setup_test_environment()
# Keep track of original storages.
settings._original_media_root = settings.MEDIA_ROOT
settings._original_file_storage = settings.DEFAULT_FILE_STORAGE
settings._original_fields_storages = {}
# Creates a temporary directory.
settings._temp_media_dir = tempfile.mkdtemp(dir=settings.BASE_PARENT_DIR)
# Use the FileSystemStorage for tests.
settings.MEDIA_ROOT = settings._temp_media_dir
settings.DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
# Use FileSystemStorage for all model fields. This is necessary because some fields will have
# already been built using the original file system backend by the time this code runs.
for model in apps.get_models():
fields = [f for f in model._meta.fields if isinstance(f, FileField)]
for field in fields:
model_path = '%s.%s' % (model._meta.app_label, model._meta.model_name)
original_storage = (field.name, field.storage)
original_storages = settings._original_fields_storages.setdefault(model_path, [])
original_storages.append(original_storage)
field.storage = FileSystemStorage(location=settings.MEDIA_ROOT)
def teardown_test_environment(self):
super(TempMediaDiscoverRunner, self).teardown_test_environment()
# Delete the temporary directory.
shutil.rmtree(settings.MEDIA_ROOT, ignore_errors=True)
# Restore original storage.
settings.MEDIA_ROOT = settings._original_media_root
settings.DEFAULT_FILE_STORAGE = settings._original_file_storage
# Restore original storages for all model fields.
for model_path, original_storages in settings._original_fields_storages.items():
model = apps.get_model(*model_path.split('.'))
for field_name, original_storage in original_storages:
field = model._meta.get_field(field_name)
field.storage = original_storage
del settings._original_media_root
del settings._original_file_storage
del settings._original_fields_storages
@coredumperror
Copy link
Author

Put test_runner.py in your main project directory, then add the following to your testing settings:

# Use a test runner that switches the file storage backend to django's default of FileSystemStorage.
TEST_RUNNER = '<< project_name >>.test_runner.TempMediaDiscoverRunner'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment