Testing Django Project - 1/Testing Django Project - 2

Learn via video courses
Topics Covered

Overview

You can build good code, detect errors, and write documentation with the help of testing. Setting up tests will make sure that you are informed if a particular function malfunctions. Tests make it significantly quicker and less expensive to fix code errors.

Any Django project must include testing, yet this step is frequently skipped. In this article, we'll go through examples of good testing code that can be used in any Django app as well as testing recommended practices.

Pre-requisites

  • Python 3.0+ must be installed.
  • Basic hands-on Django framework.

Introduction

Testing is a collection of methods to ascertain whether an application is operating correctly under a set script. Testing's primary goal is to find the application's flaws so that they can be identified and fixed. It merely shows that a product doesn't perform in a few particular circumstances, not that it always works as intended. Testing entails both the analysis and execution of the code in various settings and environments, as well as the complete code analysis.

When to Run Tests?

You will almost run across bugs when writing new code, whether you expect them to or not. A system that has undergone testing is more dependable and efficient, which raises the standard of your coding. The quality increases as more test cases are created and used for a system. However, because a web application is made up of several levels, from HTTP level request handling to validating and processing forms to rendering templates, testing a web application can be challenging at times.

You can mock requests, add test input for test cases, evaluate and comprehend your application's output, and then alter your code as necessary using Django's test execution architecture and many services.

Types of Testing

The two primary types of tests are unit and integration tests:

  • UNIT TESTING: Django unit testing concentrates on each method separately. It employs a common Python library's unittest module to create tests using a class-based methodology. Several subtests fall under the umbrella of unit testing, including testing URLs, views, models, forms, and APIs. We can use these tests separately in Django.
  • INTGRATION TESTING: While Integration Tests are more comprehensive tests, they concentrate on user behavior and application testing as a whole. To put it another way, integration testing integrates the functionality of various parts of code to ensure that they operate as intended. Integration tests are aware of the necessary interconnections between components.

What Does Django Provide for Testing?

A test framework built on a slim hierarchy of classes from the Python standard unittest library is provided by Django. Despite its name, this test framework is appropriate for both integration and unit testing. To aid in testing web and Django-specific functionality, the Django framework includes API methods and tools. Additionally, Django offers an API (LiveServerTestCase) and tools for integrating with various testing frameworks, such as the well-known Selenium framework to simulate user interaction with a live browser.

To create a test, you must inherit from one of the SimpleTestCase, TransactionTestCase, TestCase, or LiveServerTestCase Django (or unittest) test base classes, and then write distinct methods to verify that a particular functionality performs as intended (tests use "assert" methods to test that expressions result in True or False values, or that two values are equal, etc.) The framework runs the selected test methods from your derived classes when you begin a test run. The test methods are executed independently, as demonstrated in the example below, with the class defining common setup and/or tear-down behavior.

Best Practices for Django Testing

  • Test structure to see whether it can break (structure includes Models, views, forms, templates, validators, and other components).
  • You should attempt to make your tests extremely specific by testing one element at a time. In this manner, if a test fails, you can rapidly scan the code to determine precisely what is being tested and why it failed.
  • Simple is best. Writing tests on top of other tests is not something you want to have to do.
  • Run tests before pushing code to production every time it is PULLed or PUSHed from the repository and in the staging environment.
  • Upgrade to a more recent version of Django locally, run your test suite, correct any errors, push to the repository and staging, then test again in staging before releasing the code.

Set up Django Project for Testing

Create a Django project and application so you can follow along.

Test Structure

Your tests should be structured to satisfy your project. You can make a tests folder in place of the tests.py file, where each file contains tests for a different aspect of the application:

Testing Models

Let's create an example to understand more clearly. Here I've created a Django model for you.

Now, we'll write a basic test for the above model.

In the above testing code, we've seen how we are comparing two value to check if the output is as same as our desired output or not.

To execute the above test, open terminal and run:

The output will be:

Testing Views

Let’s create an example to understand more clearly. Here I’ve written a Django view concerning the above models.py.

Now, we'll write a basic test for the above view method.

To execute the above test, open the terminal and run: python python manage.py test example/tests

Output will be:

Testing Forms

Let’s create an example to understand more clearly. Here I’ve write added a comment model in models.py and created a forms.py in the application folder.

Now, we'll write a basic test for the above forms.py.

In the above code, our initial check test_init should confirm that the enter keyword argument is accepted by our form's __init__ function. By allowing our form to accept an entry keyword argument, we want to connect our comments to entries. This is how we'd like to use our CommentForm, assuming it has been written.

Secondly, Our next test test_init_without_entry should verify that if no enter keyword argument is provided, our form produces an exception.

Lastly, the setUp function for our tests adds a new database entry. For each test in the supplied test class to be able to use the User and Entry, the setup function is called first.

RequestFactory

Together with the test client, the RequestFactory uses the same API. But rather than acting like a browser, the RequestFactory gives users a means to create a request instance that can be passed as the first argument to any view function itself. It follows that you can test a view function in the same way you would test any other function: as a black box, with precisely known inputs, checking for respective outputs. The test client API is a subset of the RequestFactory's API, which is slightly more constrained:

  • The only HTTP methods that are available to it are get(), post(), put(), delete(), head(), options(), and trace ().
  • Other than the following, these methods take the same parameters. You must manage the answer because this is merely a factory for creating requests.
  • The use of middleware is not supported. If required for the view to perform properly, session and authentication attributes must be supplied by the test itself.

Test Runner

You might want to utilize the Django test runner to run your test suite if you're creating a reusable application so that you can take advantage of the Django testing infrastructure.

A class that defines the run tests() function is a test runner. The DiscoverRunner class that comes with Django specifies the standard testing behavior. This class defines the run tests() entry point as well as several other methods that run tests() use to build up, run, and finish the test suite.

Code Coverage in Django

The most widely used Python coverage measurement tool is called coverage. It records which lines of application code are reached during your tests, which ones are skipped (such as comments), and which ones are never accessed. It generates a report at the conclusion that lists the lines of code that were not run, highlighting any gaps in your test coverage.

Coverage and the nose testing tool work well, and Django-nose connects everything to Django.

  • Setup

Output:

  • Run coverage

To test the working of the coverage, we are running it in the project example we see above.

Output:

  • After the first pass you can get a coverage report by

Output:

  • Generate an HTML report with (a new folder called htmlcov will appear inside the project root)

Output:

Directory view

DIRECTORY VIEW

Conclusion

A quick recap of the points you learned today:

  • You can build good code, detect errors, and write documentation with the help of testing.
  • Testing's primary goal is to find the application's flaws so that they can be identified and fixed.
  • A system that has undergone testing is more dependable and efficient, which raises the standard of your coding.
  • The two primary types of tests are unit and integration tests: Unit testing and integration testing.
  • Some best practices for testing.
  • RequestFactory gives users a means to create a request instance that can be passed as the first argument to any view function itself.
  • You might want to utilize the Django test runner to run your test suite if you're creating a reusable application so that you can take advantage of the Django testing infrastructure.