Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django unit test client response has empty context

I have a unit test that's failing in an assertion that passes in another test in the same test case class.

Here's the passing test:

def test_home(self):
    c = Client()
    resp = c.get('/')
    self.assertEqual(resp.status_code, 200)
    self.assertTrue('a_formset' in resp.context)

Here's the failing test:

def test_number_initial_number_of_forms(self):
    c = Client()
    resp = c.get('/')
    self.assertEqual(resp.context['a_formset'].total_form_count(), 1)

In the second test, I get the error TypeError: 'NoneType' object has no attribute '__getitem__'.

If I execute the second test as

def test_number_initial_number_of_forms(self):
    c = Client()
    resp = c.get('/')
    self.assertTrue('a_formset' in resp.context)
    self.assertEqual(resp.context['a_formset'].total_form_count(), 1)

I get the error TypeError: argument of type 'NoneType' is not iterable. I've confirmed via print statements in the second test that the response.content contains the page I expect to get, that the status code is correct, and that the template is correct. But the response's context is consistently None in the second test.

I'm running my Django unit tests through the standard "python manage.py test ..." interface, so I don't believe I'm running into the "context is empty from the shell" issue.

What's going on with this?

Edit:

If I add print type(resp.context['a_formset']) to each test, for the working test I get <class 'django.forms.formsets.AFormFormSet'>. For the non-working test, I get TypeError: 'NoneType' object has no attribute '__getitem__' again.

like image 822
Melissa Avery-Weir Avatar asked Jan 18 '13 04:01

Melissa Avery-Weir


3 Answers

It's because you ran into some error, exited the shell and restarted it.

But you forgot to start environment...

from django.test.utils import setup_test_environment
>>> setup_test_environment()

That was my problem. Hope it works...

like image 195
Nabin Avatar answered Oct 20 '22 23:10

Nabin


Today I run into the same issue. The second test gets same page has nothing in response.context

I made a research and found that 1) test client uses signals to populate context, 2) my view method is not called for the second test

I turned on a debugger and found that the guilty one is 'Cache middleware'. Knowing that I found this ticket and this SO question (the latter has a solution).

So, in short: the second request is served from cache, not from a view, thus a view is not executed and test-client doesn't get the signal and have no ability to populate context.

I can not disable cache middleware for my project, so I added next hack-lines into my settings:

if 'test' in sys.argv:
   CACHE_MIDDLEWARE_SECONDS = 0

Hope this helps someone

like image 5
akava Avatar answered Oct 21 '22 01:10

akava


You can also clear cache manually by calling cache.clear() inside a test method:

from django.core.cache import cache
import pytest


class TestPostView:

    @pytest.mark.django_db(transaction=True)
    def test_index_post(self, client, post):
        cache.clear()
        response = client.get('/')
like image 1
Maxim Karpov Avatar answered Oct 21 '22 00:10

Maxim Karpov