New asserts to make it easier make it easier to work with html forms

I know that currently django includes a number of HTML specific asserts, but often in testing you don’t care or know exactly the html that will be served in a particular instance - for example - when serving a django form, as a tester performing black box testing, I care only about the whether specific fields exist on a form, and not the specifics of the HTML being used to render those fields.

I would be useful then for the Django SimpleTestCase to be extended to include asserts which just check for the existence of particular types of html construction (without needing to test for specific html) - examples would include :

  • assertHasInputs(response, expected_input_fields) : asserts that the expected input fields exist in the response content (useful when testing for a form)
  • assertHasInputValues(response, expected_fields_and values) : here ‘expected_fields_and values’ is a dictionary of field names and expected values (useful when testing edit forms).
  • assertSelected(response, select_field, expected_values) : here ‘select_field’ is the name of an html select field and ‘expected_values’ is a sequence of the values that we expect the field to be selected

It might be useful for there to be asserts around things like HTML hidden fields, existing buttons, and other possible features for html.

Having these asserts along with the Test Client would mean that test cases which need to test what users see could be closer to black box (ie not depdendent on the specific implementation of the templates).

1 Like

Hello @TonyFlury! I would personally find these very helpful (as a Django user), but as a Django developer I think that the proposed assertions are a bit overly specialized code to be suitable to add next to the current testing helpers.

My first reaction when reading this post is “this would be an amazing third party app”. Have you, by any chance, check if there is something similar our there? I know that there is GitHub - revsys/django-test-plus: Useful additions to Django's default TestCase for example.

Thanks! Natalia.

Thanks for your answer - personally it suprises me that these aren’t part of the testing ability., since part of the point of django is simple development of complex web applications.

Django provides a lot of features designed to reduce or even entirely remove the need to remove to write any HTML (unless you want to do complex styling), and also abstracts away the specific HTML of most form elements (remember it is meant to be ‘web development for people with deadlines’) - the template for a working form can be as simple as

<html>
<body>
  <form method='POST'>
  {{form}}
   <input type='submit'/>
</form>
</body>
</html>

If the template is this simple, then to test a form being served in order to that the form has all of the expected form elements (and use the out of the box capability) you need to know the exact HTML that Django will generate: this means that black box testing is entirely impossible (by default) - if Django really wants to live up to it’s slogan than the testing should only require the same knowledge of HTML as the development, so you should be able to test that the form contains the correct input items, and not do this by digging into the html that gets generated.

1 Like

Actually, a “testing purist” would say that you’re looking to test the wrong thing with that example. You want to test code that you create, and rely upon the package(s) being used to test their own code. (You should be very clear in your own mind exactly what it is that you’re trying to test whenever you write one.)

In this situation, you are not responsible for converting the Django form to HTML - that’s the responsibility of Django. Django should supply the tests that verify that a form is properly converted to HTML.

(If you don’t trust Django’s tests, then you would want to rewrite all of the Django-provided tests.)

I am sorry Ken but I disagree - I am not trying to test Django’s ability to convert a form to html - which is why the django testing system that only provides for basic HTML matches are inadequate - they would simply be repeating testing that django itself should be doing.

By testing that the forms has the right fields, I am trying to test two things that are not under Django’s control :

  1. the template itself - which I have to write and therefore have to test - the default simple template would only work if i did not care about the layout and formatting of the form itself. The only way to test the template is to use the client (or similar) to get the template rendered and then ensure that the fields that we need are available: currently to do that I have to use beautiful soup to parse the html - effectively therefore testing (in part), and tied to Djangos HTML production.

  2. That the form class is written correctly by me such that the fields that the user needs are visible. Again, using a modelForm with a simple fields = ["__all__"] is rarely what we need, so we might have a form which looks across multiple models, or have different forms in different cases. Again the exact configuration of the form needs to be tested, and can’t be tested any other way unless i do something too simplistic and instantiate the form and check that the right fields exist - but that still leaves the problem of testing that the template contains the right fields in the right way.

I absolutely trust Django to produce the html for the template and form i provide - I don’t trust me (or any other developer) to write the template correctly or to have configured the form correctly to include the fields correctly.

Django isn’t magic - it has to be configured to produce the right things at the right time in the right way, and the only way to test that configuration produces the desired results (in terms of the expected fields on the forms).

I don’t think we disagree all that much. However, I think you may be extending my comment beyond its original intent.

I was only addressing the specific example you supplied:

{{ form }}

Any unit test you write for this is redundant with Django’s test suite.

A unit test is supposed to be targeted and limited. It’s not a unit test if you are exhaustively testing every form you are creating - that’s more in the category of an integration test or an acceptance test. You don’t write a unit test for every data value your system is expected to process. You write a unit test to provide sample coverage across the scope of the application.

I am not saying those types of tests don’t have value.

I am not saying you shouldn’t have those types of tests.

What I am saying is that the Django SimpleTestCase is not the most appropriate place for these types of assertions. Again, speaking from the perspective of a “testing purist” (which I am not, btw), it would be more proper to create a subclass of SimpleTestCase containing those asserts. (That also helps identify a basis for making this into a third-party app to see just how valuable they may be.)

Cheers!