31👍
It depends what you are trying to test. I would target your tests a bit more finely than it sounds like you are doing.
If the code you need to test is the form validation logic, then I would simply instantiate the form class directly in your tests, pass it various data dictionaries and call .is_valid(), check for the proper errors or lack thereof. No need to involve HTML or HTTP requests.
If it’s view logic (which IMO should be minimized) that you are testing, you will probably want to use the test client, but you shouldn’t need to do multi-stage tests or very many tests at this level. In testing view logic I wouldn’t scrape HTML (that’s testing templates), I’d use response.context to pull out the form object from the context.
If what you want to test is that the templates contain the proper HTML to make the form actually work (in order to catch errors like forgetting to include the management form for a formset in the template), I use WebTest and django-webtest, which parse your HTML and make it easy to fill in field values and submit the form like a browser would.
29👍
You can use response.context
and form.initial
to get the values you need to post:
update_url = reverse('myobject_update',args=(myobject.pk,))
# GET the form
r = self.client.get(update_url)
# retrieve form data as dict
form = r.context['form']
data = form.initial # form is unbound but contains data
# manipulate some data
data['field_to_be_changed'] = 'updated_value'
# POST to the form
r = self.client.post(update_url, data)
# retrieve again
r = self.client.get(update_url)
self.assertContains(r, 'updated_value') # or
self.assertEqual(r.context['form'].initial['field_to_be_changed'], 'updated_value')
- [Django]-How to receive POST data in django
- [Django]-How to add an HTTP header to all Django responses
- [Django]-Django- Get Foreign Key Model
23👍
django-webtest is perfect for such tests:
from django_webtest import WebTest
class MyTestCase(WebTest):
def test_my_view(self)
form = self.app.get('/my-url/').form
self.assertEqual(form['my_field_10'].value, 'initial value')
form['field_25'] = 'foo'
response = form.submit() # all form fields are submitted
In my opinion it is better than twill for django testing because it provides access to django internals so native django’s response.context
, response.templates
, self.assertTemplateUsed
and self.assertFormError
API is supported.
On other hand it is better than native django test client because it has much more powerful and easy API.
I’m a bit biased 😉 but I believe that django-webtest is now the best way to write django tests.
- [Django]-Is there a way to loop over two lists simultaneously in django?
- [Django]-Django Local Settings
- [Django]-TypeError while using django rest framework tutorial
5👍
It’s not clear but one guess is that you have tests like this.
class TestSomething( TestCase ):
fixtures = [ "..." ]
def test_field1_should_work( self ):
response= self.client.get( "url with form data already populated" )
form_data = func_to_get_field( response )
form_data['field1']= new value
response= self.client.post( "url", form_data )
self.assert()
def test_field2_should_work( self ):
response= self.client.get( "url with form data already populated" )
form_data = func_to_get_field( response )
form_data['fields']= new value
response= self.client.post( "url", form_data )
self.assert()
First, you’re doing too much. Simplify.
class TestFormDefaults( TestCase ):
fixtures = [ "some", "known", "database" ]
def test_get_should_provide_defaults( self ):
response= self.client.get( "url with form data already populated" )
self.assert(...)
The above proves that the defaults populate the forms.
class TestPost( TestCase ):
fixtures = [ "some", "known", "database" ]
def test_field1_should_work( self ):
# No need to GET URL, TestFormDefaults proved that it workd.
form_data= { expected form content based on fixture and previous test }
form_data['field1']= new value
response= self.client.post( "url", form_data )
self.assert()
Don’t waste time doing a “get” for each “post”. You can prove — separately — that the GET operations work. Once you have that proof, simply do the POSTs.
If you POSTS are highly session-specific and stateful, you can still do a GET, but don’t bother parsing the response. You can prove (separately) that it has exactly the right fields.
To optimize your resting, consider this.
class TestPost( TestCase ):
fixtures = [ "some", "known", "database" ]
def test_many_changes_should_work( self ):
changes = [
( 'field1', 'someValue', 'some expected response' ),
( 'field2', 'someValue' ),
...
]
for field, value, expected in changes:
self.client.get( "url" ) # doesn't matter what it responds, we've already proven that it works.
form_data= { expected form content based on fixture and previous test }
form_data[field]= value
response self.client.post( "url", form_data )
self.assertEquas( expected, who knows what )
The above will obviously work, but it makes the number of tests appear small.
- [Django]-How to get URL of current page, including parameters, in a template?
- [Django]-How to I show a list of ForeignKey reverse lookups in the DJango admin interface?
- [Django]-@csrf_exempt does not work on generic view based class
1👍
Think carefully about why you need to unit-test this. Forms are part of the core Django functionality, and as such are very well covered by Django’s own unit tests. If all you’re doing is basic create/update, which from your question it sounds like is the case, I don’t see any reason to write unit tests for that.
- [Django]-In PyCharm, how to navigate to the top of the file?
- [Django]-Django request get parameters
- [Django]-Django submit two different forms with one submit button
0👍
You are possibly looking for tools that do front end testing like twill or selenium
Both of these generate python code, that can be included within the django tests, so when you run tests, it opens the urls, posts the data and inspects whatever you want!
It should help you to see these tests written for selenium, for an open source reusable django app.
- [Django]-Django – How to rename a model field using South?
- [Django]-What is the best way to upload files in a modern browser
- [Django]-Reducing Django Memory Usage. Low hanging fruit?
0👍
I don’t see how or why you need unit tests for this. Sounds to me like you’re testing for (and correcting) possible user input, which is covered very simply with Django’s form validation (and model validation in 1.2)
- [Django]-Disable HTML escaping in Django's TextField
- [Django]-Django aggregate or annotate
- [Django]-How to write a query to get find value in a json field in django
0👍
I’d recommed you to take a look into acceptance testing level tools like robot test framework or letucce which are thought just for you want to do “I’m verifying that my application produces correct responses when a user makes changes to a form”, that sounds more like acceptance (black-box) testing than unit-testing.
For instace, Robot let you to define your tests in tabular form, you define the workflow once and then you can define easily a bunch of tests that exercise the workflow with different data.
- [Django]-Django – Can you use property as the field in an aggregation function?
- [Django]-Django model one foreign key to many tables
- [Django]-Django request to find previous referrer