Testing views for Django involves a lot of repetitive code. Each test case evaluates similar cases:
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.
django-skivvy provides a mixin ViewTestCase
to add additional helper methods to your test case.
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.
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
, post_data
, session_data
, view_kwargs
and content_type
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 authenticated 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. |
session_data |
dict |
{} |
If your view relies on data from the session store, you can provide this data using
session_data
. |
view_kwargs |
dict |
{} |
Overwrites attributes set in the view class. The behaviour corresponds to
providing keyword arguments to a class-based view's as_view() method
. |
content_type |
str |
application/json |
Only available for APITestCase
. Sets the content type encoding for the request. |
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. |
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.
To create model instances that are required in your test, add the method setup_models
to the test case.
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.
view_class
setup_view()
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.
url_kwargs
setup_url_kwargs
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.
get_data
setup_get_data
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.
request_meta
setup_post_data
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:
post_data
setup_post_data
If the view class you are testing is a ViewSet
, then you have to configure viewset_actions
in the test case.
viewset_actions
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.
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.
template
setup_template
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.
template_context
setup_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.
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.
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
.
success_url
Use this to define a static success URL.
success_url
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.
success_url_kwargs
setup_success_url_kwargs
get_success_url()
Finally, overwriting the method get_success_url()
provides the most flexibility.
get_success_url()