Repository: pytest-dev/pytest-django (python)

Issue:
Tests with django sites framework onetoonefield causes unexpected behavior
Assume you have a model:

```
class Customer(models.Model):
    site = models.OneToOneField('sites.Site')
```

And when using the sites middleware, without setting SITE_ID, the site is looked up and cached based on the requests host information: https://github.com/django/django/blob/master/django/contrib/sites/models.py#L12

This causes unexpected behavior if testing a multi tenant site, as the request.site object will be the one from the SITE_CACHE, that might have an already populated _request.site.customer_ from previous execution.

I will submit a proposal for fixing this, as it can cause plenty of pain when debugging :)



Discussion:

Patch:
diff --git a/pytest_django/plugin.py b/pytest_django/plugin.py
--- a/pytest_django/plugin.py
+++ b/pytest_django/plugin.py
@@ -539,6 +539,20 @@ def _template_string_if_invalid_marker(request):
             else:
                 dj_settings.TEMPLATE_STRING_IF_INVALID.fail = False
 
+
+@pytest.fixture(autouse=True, scope='function')
+def _django_clear_site_cache():
+    """Clears ``django.contrib.sites.models.SITE_CACHE`` to avoid
+    unexpected behavior with cached site objects.
+    """
+
+    if django_settings_is_configured():
+        from django.conf import settings as dj_settings
+
+        if 'django.contrib.sites' in dj_settings.INSTALLED_APPS:
+            from django.contrib.sites.models import Site
+            Site.objects.clear_cache()
+
 # ############### Helper Functions ################
 
 


Test patch:
diff --git a/tests/test_environment.py b/tests/test_environment.py
--- a/tests/test_environment.py
+++ b/tests/test_environment.py
@@ -3,9 +3,12 @@
 import os
 
 import pytest
+from django.contrib.sites.models import Site
+from django.contrib.sites import models as site_models
 from django.core import mail
 from django.db import connection
 from django.test import TestCase
+from pytest_django.lazy_django import get_django_version
 
 from pytest_django_test.app.models import Item
 
@@ -215,3 +218,26 @@ def test_more_verbose_with_vv_and_reusedb(self, testdir):
             "*PASSED*"])
         assert ("*Destroying test database for alias 'default' ('*')...*"
                 not in result.stdout.str())
+
+
+@pytest.mark.skipif(
+    get_django_version() < (1, 8),
+    reason='Django 1.7 requires settings.SITE_ID to be set, so this test is invalid'
+)
+@pytest.mark.django_db
+@pytest.mark.parametrize('site_name', ['site1', 'site2'])
+def test_clear_site_cache(site_name, rf, monkeypatch):
+    request = rf.get('/')
+    monkeypatch.setattr(request, 'get_host', lambda: 'foo.com')
+    Site.objects.create(domain='foo.com', name=site_name)
+    assert Site.objects.get_current(request=request).name == site_name
+
+
+@pytest.mark.django_db
+@pytest.mark.parametrize('site_name', ['site1', 'site2'])
+def test_clear_site_cache_check_site_cache_size(site_name, settings):
+    assert len(site_models.SITE_CACHE) == 0
+    site = Site.objects.create(domain='foo.com', name=site_name)
+    settings.SITE_ID = site.id
+    assert Site.objects.get_current() == site
+    assert len(site_models.SITE_CACHE) == 1