Skip to content

Testing code

Dutcher edited this page Mar 3, 2023 · 1 revision

Testing code

The code in this repository is tested with Djangos built-in testing tools which you can read up in the testing tools documentation. However, there are arguably testing tools lacking in this set. Therefore additional testing tools can be found the utils.testing module.

We use Codecov to validate whether testcases reach all lines in the code. However that does not indicate whether certain output is validated. For instance when testing a view with a form, merely running a GET request on that view marks code in the form class as executed, this does not mean that there are testcases for those lines in the code. It is up to you to ensure future alterations don't accidentally break your code without being detected in the testcases.

It is useful to write a testcase to:

  • ensure that certain classes use other (tested) classes. (e.g. a FormView class uses a specific Form)
  • ensure requirements on a piece of code are checked for (e.g. a view requires a permission or an object is required to be in a certain state)
  • test for specific edge cases that may otherwise easily be missed (e.g. recurrent activities take daylightsavings into account)

Testing Forms

For testing forms it is advised to use the FormValidityMixin, this mixin for the TestCase class sets up forms with the classes avoiding more repetitive initialisation methods. The various assert methods in this class use the build_form() method to construct the form and do their logic taking care of a lot of overhead. Make sure to set the class form_class property.

from django.test import TestCase
from utils.testing import FormValidityMixin

class MyFormTestCase(FormValidityMixin, TestCase):
    fixtures = ["my_fixtures"]  # fixtures setting up some database values.
    form_class = MyForm

    def get_form_kwargs(self, **kwargs):
        kwargs.setdefault('instance', MyModel.objects.get(id=1))
        return super(MyFormTestCase, self).get_form_kwargs(**kwargs)

assertHasField(field_name, form_kwargs=None, **field_properties)

Assert that the form has a field with the given field_name Use form_kwargs whenever you want to override certain form_kwargs (except for data). This can be useful when you want certain fields to behave different for different form_kwargs. For instance based on the state of the model instance fed into the form. Use field_properties to check if the given field also has certain properties or append __class behind the property to check for class instance.

def test_my_field(self):
   """ Test that MyForm.my_field is correctly set up """
   my_model = MyModel.objects.get(id=2)

   self.assertHasField(
      'my_field',                         # field name
      form_kwargs={'instance': my_model } # override (partial) form kwargs (optional)
      required=True,                      # Field should be required (optional field_property)
      widget__class=TextInput,            # Field should use TextInput widget (optional field_property)
   )

assertFormValid(data, form_class=None, **form_kwargs)

Assert that the form with the given data dictionary is valid. Use kwargs to override any form init kwargs. It returns the valid form for any future use.

def test_form_saving(self):
   """ Test form valid """
   form = self.assertFormValid({'my_field': "some value"})
   form.save()
   # Insert saving validation logic

assertFormHasError(data, code, form_class=None, field=None, **kwargs)

Assert that a form raises an error for a given data dictionary. The exception should contain a code as defined in the form validation guidelines. Use field to ensure that a specific field throws the error. If no error matching the given code and (if set) field is found it raises an assertionerror which includes any possible other errors it did find

def test_clean_myfield(self):
    self.assertFormHasError(
        {'my_field': "the game"}, # The form data
        'forbidden-word-used'),   # The error code
        field_name='my_field'     # The name of the field that has the code (optional)
    )

Testing Views

To be written