Testing in Django

This is the 11th day of my participation in the August More Text Challenge. For details, see:August is more challenging

For web developers today, automated testing is a very useful tool for bug discovery. You can use a set of tests – a test suite – to solve and avoid a bunch of problems:

  • When you write new code, you can use tests to ensure that the code works as expected.
  • When you do not modify or modify old code, you can use tests to ensure that your changes do not cause the application to run erratically.

A Web application is a job for Arctic testing, because the Web application contains the real business logic — from the HTTP layer responding to requests, to form status detection and processing, to template rendering. Using Django’s test execution framework and associated tools, you can simulate it by inserting test data, checking the application’s output, and testing to see if your code needs to run.

The preferred way to write tests in Django is to use the built-in modules of the unittestPython standard library.

You can also use another Python testing framework

1. Normal unit tests

One piece of code tests another

from django.test import TestCase
import unittest
​
​
# Create your tests here.
​
def add(x, y):
    return x + y
​
​
class My_test(unittest.TestCase):
    def test1(self):
        c = add(1, 3)
        self.assertEqual(c, 4)
​
    def test2(self):
        c = add(2, 3)
        self.assertEqual(c, 5)
​
    def test3(self):
        c = add(1.1, 3)
        self.assertEqual(c, 4)
​
​
if __name__ == '__main__':
    unittest.main()
Copy the code

2. Django model (models.py) tests

Tests that require a database (that is, model tests) will not use your “real” (production) database. Create a separate, empty database for your tests.

When all tests have been executed, whether the tests have passed or failed, the test database is destroyed.

Django uses the standard Python unittest module. This module defines tests in the form of classes.

from django.test import TestCase from myapp.models import Animal class AnimalTestCase(TestCase): # TestCase def setUp(self): Animal. Objects.create (name=" roar", sound="roar") Animal. Objects.create (name=" roar", sound="roar") sound="meow") def test_animals_can_speak(self): """Animals that can speak are correctly identified""" lion = Animal.objects.get(name="lion") cat = Animal.objects.get(name="cat") self.assertEqual(lion.sound, "roar"') self.assertEqual(cat.sound, "meow")Copy the code
Python manage. Py test. / the manage. Py test animals. The tests. The AnimalTestCase. # test_animals_can_speak tests under the pathCopy the code

Pay attention to

If your tests rely on database connections, such as create or model, be sure to inherit from djangos.TestCase to implement your test class, not unittest.testCase. Using unittest.testCase avoids running each test and refreshing the database in a transaction, but if your tests interact with the database, their behavior will vary depending on the order in which the test runner executes them. This can cause unit tests to pass when run individually but fail when run in a suite.Copy the code

3. The order in which tests are executed

To ensure that all TestCase code starts from a clean database, the Django test runner reorders the tests in this way:

  • TestCaseFirst run all the subclasses.
  • Then, all other Django-based tests (based onSimpleTestCase, including test casesTransactionTestCase) run without a particular order guaranteed or enforced.
  • thenunittest.TestCaseRun any other tests (including doctests) that might change the database without restoring it to its original state.

4, the instance,

from django.test import TestCase import unittest from .models import UserInfo class UserTest(TestCase): def setUp(self) -> None: Create (username=" ABC ", email="[email protected]", mobile_phone="111", password="123456") UserInfo.objects.create(username="abc1", email="[email protected]", mobile_phone="122211", password="12345678") def test_create(self): Userinfo.objects. create(username="abc2", email="[email protected]", mobile_phone="111111", password="123456") p = UserInfo.objects.get(username="abc2") self.assertEqual(p.username, "abc2") self.assertEqual(p.mobile_phone, "111111") def test_delete(self): P = userinfo.objects.get (username="abc2") p.delte () ret = userinfo.objects.filter (username="abc2") self.assertEqual(ret.username, "abc2") def test_update(self): P = userinfo.objects.get (username=" ABC ") p.appname ="cba" p.appname () ret = userinfo.objects.get (username="cba") self.assertEqual(ret.username, "cba")Copy the code

Understanding test output

When you run the tests, you see many messages as the test runner prepares itself. You can control the level of detail of these messages using verbosity using options on the command line:

Creating test database...
Creating table myapp_animal
Creating table myapp_mineral
Copy the code

This tells you that the test runner is creating a test database, as described in the previous section.

After you create the test database, Django will run your tests. If all goes well, you should see something like this:

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 22 tests Ran in 0.221 s OKCopy the code

However, if any tests failed, you will see complete details about which tests failed:

====================================================================== FAIL: test_was_published_recently_with_future_poll (polls.tests.PollMethodTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "/dev/mysite/polls/tests.py", line 16, in test_was_published_recently_with_future_poll self.assertIs(future_poll.was_published_recently(), False) AssertionError: True is not False -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Ran 1 test in 0.003 s FAILED (failures=1)Copy the code

A complete explanation of this error output is beyond the scope of this document, but it is straightforward. You can consult the documentation for the Pythonunittest library for details.

Note that for any number of failed and error tests, the test-runner script has a return code of 1. If all tests pass, the return code is 0. This is useful if you are using test-runner scripts in shell scripts and you need to succeed or fail tests at that level.