Run Django Tests

  1. Figure 1: Test results in my build that shows results of my python unit tests. The build will run all python tests in all of my source code folder, thanks to Pytest that does everything for you, both discovering and run all tests in the folder. If code does not compile, unit test will fail and you have a failing build.
  2. The best base class for most tests is django.test.TestCase. This test class creates a clean database before its tests are run, and runs every test function in its own transaction. The class also owns a test Client that you can use to simulate a user interacting with the code at the view level.

Note: this tutorial builds on the skills and code developed in How to Create an API with Django. We will be working on the same ToDo list API, using this version on GitHub.

Last summer, I was working on a Django web application with some of my friends. One time, I completed a feature and sent it to another guy to test. He replied that he couldn't test the new feature because I'd inadvertently broken the sign in function. The problem was, this didn't just happen one time, something like it happened every week. The underlying issue was that our workflow didn't include sufficient automated testing.

Testing in Django¶. Testing in Django. Automated testing is an extremely useful bug-killing tool for the modern Web developer. You can use a collection of tests – a test suite – to solve, or avoid, a number of problems: When you’re writing new code, you can use tests to validate your code works as expected. When you’re refactoring or modifying old code, you can use tests to ensure your changes haven’t. Python tester allows to test Python code Online without install, all you need is a browser. You can test your Python code easily and quickly. You can test your Python code easily and quickly. This python sandbox uses Brython (BSD 3-Clause 'New' or 'Revised' License), it is a Python 3 implementation for client-side web programming. Ensure the test passes. This has been a basic guide on how to configure Celery to run long-running tasks in a Django app. You should let the queue handle any processes that could block or slow down the user-facing code.

What is automated testing?

Testing your code is an essential part of programming. Depending on your project, you might test your code by looking at a web page, playing through a video game, or analyzing output logs. Manual testing is time-intensive and leaves room for error, so most professional programmers dedicate serious attention to automated testing. Today, we are going to review a common type of automated testing, unit tests, to consider how automated testing can help us during the development process. First, we will write tests on the models and views of the existing API, then practice test-driven development by adding a new feature.

Automated testing saves time and improves software quality. Manual testing is quick when getting started: just run the code and see if it works. However, over time, you develop more and more features in the application, turning manual testing very time-intensive. Furthermore, you might forget to test a certain function. A proper implementation of automated testing covers everything, every time, in seconds. Having good automated testing also makes it easier for other people to understand your code and enables teams to build things together without worrying about breaking each others' features.

A unit test verifies the functionality of a component individually. It is the lowest level of testing; it makes sure that each aspect of the program works correctly alone (integration and systems tests validate the components together and their interactions, but that is beyond the scope of this tutorial). For example, in an object-oriented program, you would write unit tests for each object and, depending on the complexity, for individual methods. In Django, we unit test each model and view.

How does Unit Testing in Django work?

To follow along with this tutorial, clone the project from GitHub. Follow the same steps to set up the project as the first three paragraphs of How to Create an API with Django.

Tests

When you use python manage.py startapp appname to create a Django app, one of the files Django creates in the appname directory is called tests.py. This file exists to house unit tests for models and other components within the app. By default, the file contains one line of code: from django.test import TestCase. A Test Case contains multiple related tests for the same piece of code. TestCase is a Django object that we will inherit to build out own unit tests. The class has two methods, setUp(self) and tearDown(self), which run before and after the individual test functions to provide and clean up a testing database separate from whatever database you access with python manage.py runserver. Open up tests.py in the todo folder of the project to examine the code.

Here, we test the Sign In function. Because we are using built-in Django methods, as long as nothing is broken with the database, this should work fine, so we need only simple tests: if correct information is presented, authenticate, if incorrect information is given, don't. This test case lets us see a few more things about unit testing in Django. The first is that all test methods in a test case must begin with test_ in order to run when we execute the python manage.py test command. Other methods in the test case are considered helper functions. The other important piece is that all test methods must take self as an argument, where self is a reference to the TestCase object. TestCase, which we inherit to create our class, provides assertion methods to evaluate booleans. A self.assertSomething() call passes if the values passed as arguments are consistent with the assertion, and fails otherwise. A test method passes only if every assertion in the method passes.

Now, we test our own model: the Task object defined in models.py. To set up the test case we create a user and a task (note that because of the ForeignKey relationship between task and user, deleting the user in tearDown() also deletes the task). Here, we see that any test method can have multiple assertions, and passes only if all assertions succeed. We can write to the database outside of the setup function, which we do when updating the task. Otherwise, this is a very similar test to the sign up test, indeed, most model test cases are just about creating, reading, updating, and destroying objects in the database, though models with methods are more interesting to test.

Django Test Example

Testing views is somewhat more complicated than testing models. However, as we are writing an API, we don't have to worry about testing the front end like we would in a web app. Thus, we can replace much of our formerly manual testing via Postman with views tests. self.client is an HTTP client within the Django testing library. We use it to make a post request to '/signin/' with the user credentials. We test the same things as before: correct login info, wrong username, and wrong password. This is especially useful because it show us that if the model tests pass but the views tests fail, the issue not with the model, limiting the scope of our debugging. We do a similar thing for views related to tasks.

This case tests the '/all/' endpoint. The test case itself has more methods, but the snippet copied above shows us all of the new stuff. In the setup, we use self.client.login() so that the client acts like a logged-in user. Then, we create tasks and compare them to the formatted output that we expect. This example more clearly illustrates the benefits of the setUp() and tearDown() methods, as the tasks from one test do not carry over into the others. Again, this test isolates the view component, as the underlying model is separately tested.

Now that you understand the test code, run python manage.py test to run all tests. Let's examine the output:

All passing tests are indicated with a . while failing tests receive an F. Failing tests yield errors explaining why the assertions failed. The tests we haven't talked about yet are failing, which we will fix in the next section. Before we proceed, you may notice that this testing code is incredibly verbose. Indeed, we have only tested a small amount of our functionality, and yet the tests file is already as many lines of code as the views file. This is to be expected, you really can't have too many tests as long as they are all accurate. When you change your code, some tests will break, which simply shows you what tests you need to fix. Thus, you should expect to continuously accumulate testing code, and expect that in an average production application you will have several times as many lines of tests as lines of code.

What is Test-Driven Development?

Let me return to the opening story for a moment. After weeks of fighting though bug after bug, my team and I wrote unit tests for the entire codebase. We had complete test coverage, meaning that every line of code was verified with at least one test. This lasted for a couple of weeks, until we decided to materially change our database schema. Rather than re-write the tests, we discarded the broken ones and within days we started experiencing 'accidental breakage' bugs again. Test-driven development would have prevented this backsliding.

In order to stay useful, your tests require updating along with your code. Some programmers practice test-driven development to stay ahead of code changes. When you develop a feature, the first thing you do is define what the feature needs to do. Test-driven development formalizes this process by writing tests for that functionality first. The general idea is that you write one or more tests that define the feature, code until those tests pass, then repeat by writing more tests.

Tests

Returning to the failing tests shows us that we need to implement a due_today() method in the Task model. By examining the tests, we can see that it should return True if a task is due today, otherwise it should return False. Copy the code below to replace the existing due_today() method in the Task model then run the tests again.

The tests pass, showing that our feature works and we can proceed. This method of development requires more thought and effort at the beginning to define the behavior of the code, but makes the actual coding process much more straightforward and achievable.

Run Django Tests

To test your understanding, try writing tests for the other existing views, or use tests to define new functions and then add those features. An easy one would be a boolean field completed in the task model that could be set to true once the task was done, allowing us to retain completed tasks instead of deleting them. Then, look into adding tests to your own projects. It can be daunting to stare down a large, untested project and try to bring it to full coverage. Rather than trying to test everything at once, add tests to small chunks of the project or new features as you develop them and build up to complete coverage.

Run Django Tests Positive

Further Reference:

Run Django Tests For Free

We write about how to become a better developer and how to maintain and apply your skills. We also publish job offers and exclusive promos for more than 8000 subscribers. Join us!