19

I have a view that should be setting an initial value for a form field based on a GET value. I want to test this. I'm currently using Django's test client but I am open to looking at other tools.

Edit

Sorry, I did not mention that I am well aware of the assertContains method but I was hoping there was a better way other than searching the HTML for an input tag and the value attribute.

Belmin Fernandez
  • 7,277
  • 8
  • 46
  • 75
  • Hmm, Well you would have to make parse tree then, right? After django sends out its response its basically done. You could use something like BeautifulSoup or another html parser. But to me, at least in the case your stating, that its just running extra cycles to check for the text you want. – nate c Nov 21 '10 at 01:25
  • Here is an example how to parse the form of `response.content` and use the data in the Django TestClient: https://stackoverflow.com/a/65603777/633961 – guettli Jan 06 '21 at 21:47

5 Answers5

31

Hate to answer my own question (like the 3rd time I've done it) but after mocking around with the test client, I've found a better way:

def test_creating_stop(self):
    c = self.client

    # Check that name is pre-filled
    response = c.get('%s?name=abcd' % reverse('add_new_stop'))
    self.assertEqual(response.context['form'].initial['name'], 'abcd')

Does anyone see anything wrong with this? I'll leave it up for a while see what people think.

Belmin Fernandez
  • 7,277
  • 8
  • 46
  • 75
  • 1
    That's exactly what I was going to suggest. Its how I do it too :) – mkelley33 Nov 22 '10 at 19:32
  • 1
    Have you found that trying to take `response.context['form'].initial` where there is ForeignKeys/M2M in it and feeding that back via post will be problematic? It wants the id's not the Objects.. – rh0dium Jan 17 '12 at 16:08
  • This is what I was looking for. – arustgi May 13 '12 at 06:55
  • 3
    Its worth noting that if you are testing a Django Admin page you need to access `response.context['adminform'].form.initial` instead. –  Nov 07 '14 at 00:35
8

The accepted solution check initial['...'] value on the form but you could also check the actual value on the field. Pseudo-code bellow.

This is helpful if you want to test a default value coming directly from the model (form.initial is not set) and to make sure that initial['...'] is the actual value.

def test_some_default_value(self):
        response = self.client.get('/signup/')
        self.assertEquals(response.context['form']['plan'].value(), my_value)

def test_some_default_value_2(self):
        some_different_conditions...
        response = self.client.get('/signup/')
        self.assertEquals(response.context['form']['plan'].value(), a_different_value)
François Constant
  • 4,965
  • 1
  • 28
  • 34
2

The value will be embedded in the html as <input value= 'whatever'/>. You can search for that string with whatever tool you prefer.

response = Client().get('/customer/details/')
print [line for line in response.split('\n') if line.find('<input') > -1]
nate c
  • 7,936
  • 2
  • 23
  • 25
  • +1 Thanks Nate. However, I was hoping there was a better way than searching through the HTML source. Edited the question. – Belmin Fernandez Nov 21 '10 at 01:17
  • This is wrong for at least 2 reasons: One you are using an absolute URL rather than doing a `reverse` URL lookup, and you are scraping the HTML when Django tests make the context easily available. –  Nov 06 '14 at 23:37
0

I think this feature comes with 1.3 but it may have come in earlier. I've slightly modified the example on the page to work with your requirements, but it's untested code and I've assumed a few things like the form parameter of the response context. Modify as applicable. The point of this answer is to show the request factory.

http://docs.djangoproject.com/en/dev/topics/testing/#django.test.client.RequestFactory

from django.utils import unittest
from django.test.client import RequestFactory

class SimpleTest(unittest.TestCase):
    def setUp(self):
        # Every test needs access to the request factory.
        self.factory = RequestFactory()

    def test_details(self):
        get_param = 'some_value'
        # Create an instance of a GET request.
        request = self.factory.get('/customer/details/?param={0}'.format(get_param))

        # Test my_view() as if it were deployed at /customer/details
        response = my_view(request)

        # test 1
        form = response.form
        idx = form.as_p().find(get_param)
        self.assertNotEqual(idx, -1)            
        #or.. test 2
        self.assertContains(response, get_param)
Josh Smeaton
  • 43,953
  • 24
  • 121
  • 160
0

If you strictly checking for the initial value of a form field, another alternative is testing your form:

forms.py:

from django import forms

class MyForm(forms.Form):
    title = forms.CharField(initial='My Default Title')

test_forms.py

from django.test import TestCase
from .forms import MyForm

class MyFormTests(TestCase):
    def test_myform_initial_value(self):
        form = MyForm()
        self.assertEqual(form['title'].initial, 'My Default Title')
HBat
  • 3,195
  • 3
  • 26
  • 42