django-skivvy

Testing views for Django involves a lot of repetitive code. Each test case evaluates similar cases:

  • Accessing the view with an authorized user and returning the correct response content and status.
  • Accessing the view with an unauthorized user and return the right response content and status.
  • Accessing the view with an unauthenticated user and redirecting to the login page.
  • Accessing an object, which is not found in the database and returning a 404 error.
  • Posting a valid payload.
  • Posting an invalid payload.

Many of these cases need to be set up in similar ways. The test client needs to call the URL with specified parameters, the user needs to be logged in, an expected response needs to be rendered with a given template and template context and evaluated.

Using the Django built-in test client is very slow. So we have been experimenting with alternative approaches to testing views. Our approach, however, involves even more repetitive boilerplate code. Views need to be initialized with parameters to identify objects in the database; users need to be assigned, templates need to be rendered with specific template contexts, etc., etc.

django-skivvy is a mini test framework that addresses the problems and that helps you write better and more readable tests for Django views. You can focus on parametrizing your tests, while django-skivvy takes care of running the tests.

Testing a view

django-skivvy provides a mixin ViewTestCase to add additional helper methods to your test case.

Testing Django Rest Framework API views

To test instances of DRF's APIView, use APITestCase instead. It behaves exactly as ViewTestCase; the only difference are a few internals in the test setup.

Getting a response

The method request returns a response from your view. The response returned is based on the generic configuration of the test case.

To test special cases, you can use url_kwargs, get_data and post_data parameters to temporarily overwrite the generic test setup.

Argument Type Default Description
method str GET HTTP method used for the request
user User AnonymousUser User authticated with this request.
url_kwargs dict {} URL arguments passed to the view. ViewTestCase applies this dictionary to what is defined in url_kwargs or get_url_kwargs .
get_data dict {} Adds query parameters to the request URL. E.g., to test a request to /some/path/?filter=foo add get_data={'filter': 'foo'} .
post_data dict {} Request payload, only relevant for POST , PUT and PATCH requests. ViewTestCase applies this dictionary to what is defined in post_data or setup_post_data . Partial overwrites are allowed.
content_type str application/json Only available for APITestCase . Sets the content type encoding for the request.

Evaluating a response

request does not return a Django HTTPResponse object. The returned object provides convenient access to important response properties:

Property Type Description
status_code int HTTP status code of the response
content str , dict Content of the response. None if request results in a redirect. If the response is of type application/json , the response will be parsed into a dict .
location str Redirect location. None if the request does not result in a redirect.
messages list A list of all messages added to the session.
headers dict Dictionary of response headers returned from the view.

Example use

Test configuration

django-skivvy's test configuration borrows many ideas from Django's generic views. All details of the test configuration can be either set by a constant instance attribute or by overwriting a method, which allows you to add more logic to the test setup.

Creating model instances

To create model instances that are required in your test, add the method setup_models to the test case.

View class

Each test case should only test one view class. To configure the view class, you can use the view_class attribute or the setup_view method. One of both is required; if both view_class and setup_view provided, the method setup_view is preferred.

Attribute: view_class

Method: setup_view()

URL arguments

Many URL patterns expect certain keys, which are passed to connected views to identify model instances. These arguments need to be provided to the view in the test case. To configure URL arguments, you can set the attribute url_kwargs or implement the method setup_url_kwargs. If neither url_kwargs or setup_url_kwargs are present, an empty dict ({}) is passed to the view.

Both url_kwargs or setup_url_kwargs define default URL arguments for all tests in the test case. Sometimes you might want to test how the view behaves under varying conditions, for instance when you want to test that a 404 error is returned when a model instance cannot be found in the database. You can overwrite individual URL keys in the request method, by providing the optional url_kwargs argument:

If you have several URL arguments, and you want to overwrite only some of them, it's sufficient only to provide the keys you want to change. django-skivvy merges those with the default URL arguments.

Attribute: url_kwargs

Method: setup_url_kwargs

URL query parameters

To query parameters to the request URL, you can set the get_data attribute or implement setup_get_data(). If neither get_data or setup_get_data() are present, no query parameters will be added.

To add a search query parameter

Both get_data or setup_get_data define default request query parameters for all tests in the test case. Sometimes you might want to test how the view behaves under varying conditions, for instance, if a resource list is filtered correctly. You can overwrite selected query parameters, by providing the optional get_data argument to the request.

Attribute: get_data

method: setup_get_data

Request meta attributes

You can add additional meta attributes to the request by setting the request_meta attribute or implementing setup_request_meta().

Both request_meta or setup_request_meta define default request meta attributes for all tests in the test case. You can overwrite selected meta attributes, by providing the optional request_meta argument to the request.

Attribute: request_meta

method: setup_post_data

Request payload

To setup a default request payload for POST, PATCH or PUT request, you can set the post_data attribute or implement setup_post_data(). If neither post_data or setup_post_data() are present, the request payload defaults to {}.

Both post_data or setup_post_data define default request payloads for all tests in the test case. Sometimes you might want to test how the view behaves under varying conditions, for instance, that an invalid payload is handled correctly. You can overwrite parts of the request payload in the request method, by providing the optional post_data argument:

Attribute: post_data

method: setup_post_data

Viewsets

If the view class you are testing is a ViewSet, then you have to configure viewset_actions in the test case.

Attribute viewset_actions

Evaluating response content

To evaluate the response's content, ViewTestCase provides the property expected_content that you can use in the test's assertions.

expected_content can be configured by providing a template name and a template context.

Configuring template name

To configure the template name you can set the attribute template or implement the method setup_template of you need more logic. Either template or setup_template() are required; if both are present setup_template() will be prefered.

Attribute: template

method: setup_template

Configuring template context

To configure the template context, you can provide a static context using the template_context or implement setup_template_context(). If neither template_context or setup_template_context() are present the template context used defaults to {}; if both are present setup_template_context() will be prefered.

Attribute: template_context

Method: setup_template_context

Overwriting the template context

The combination of template and template context defines the default expected response for all tests in the test case. In some cases, you want to test if the template is rendered with an alternative context, for instance, if a form renders the error messages correctly. expected_content uses the method render_content internally. You can use the same method to render alternative views of the template by updating the default context with new values. render_content() allows to add an arbitrary number of keyword arguments, which update the default context.

Removing CSRF tokens from the response

Since version 1.10, Django changes the CSRF token on each request. If you render a template twice the CSRF token changes and comparing both results will fail.

django-skivvy removes all CRSF tokens from rendered response automatically. If you have a special case where you render a template without using django-skivvy, you can use remove_csrf to remove the token from the response.

Evaluating redirects

When a view redirects to a different location after a request, you can test that too. It is, for example, common to redirect to an object's detail page after an object is created or updated, or to redirect to the login page, when a login is required.

expected_success_url

ViewTestCase provides the property expected_success_url that you can use in the test's assertions.

There are different ways to configure what is returned from expected_success_url.

Static success_url

Use this to define a static success URL.

Attribute: success_url

URL name and URL arguments

To generate the expected_success_url, django-skivvy uses Django's reverse function. You have to provide the URL name and URL arguments to generate the success URL.

The URL name can be defined via the success_url_name attribute. The URL arguments can be provided by the static success_url_kwargs attribute or by implementing the method setup_success_url_kwargs if you need to apply more logic.

Attribute success_url_kwargs

Method setup_success_url_kwargs

Overwriting get_success_url()

Finally, overwriting the method get_success_url() provides the most flexibility.

Method get_success_url()

django-skivvy Documentation