-
Notifications
You must be signed in to change notification settings - Fork 8
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 specificForm
) - 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)
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)
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)
)
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
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)
)
To be written