官网文档———中文: https://docs.djangoproject.com/zh-hans/2.2/topics/testing/
bilibili视频配合看 https://www.bilibili.com/video/BV19k4y1B7zR?p=14 它举例了, template, view, model, ajax, Function_test 和 Unittest

单元测试 unittest

python自己带了一个单元测试框架,unittest,可以方便的实现测试环境初始化,测试用例编写(以test_开头,能自动执行 ),环境清除, 返回校验的功能,可以很方便的使用, 在这只做简单介绍。
在单元测试运行完之后,成功会打印一个”.”,失败会显示断言失败的地方。

  1. import unittest
  2. class MyTest(unittest.TestCase): # 继承unittest.TestCase
  3. def setUp(self):
  4. # 每个测试用例执行之前做操作
  5. print('22222')
  6. def tearDown(self):
  7. # 每个测试用例执行之后做操作
  8. print('111')
  9. @classmethod
  10. def tearDownClass(self):
  11. # 所有test运行完后运行一次
  12. print('4444444')
  13. @classmethod
  14. def setUpClass(self):
  15. # 所有test运行前运行一次
  16. print('33333')
  17. def run(self):
  18. print("00000") # 不是以test_开头,所以不会执行
  19. def test_a_run(self):
  20. self.assertEqual(1, 1) # test_开头, 所以是测试用例
  21. def test_b_run(self):
  22. self.assertEqual(2, 2) # test_开头, 所以是测试用例
  23. if __name__ == '__main__':
  24. unittest.main()#运行所有的测试用例

django 单元测试框架

django的单元测试是基于unittest 编写,所以整个流程和unittest的完全一致。
为了方便使用django test 有一个client,可以方便我们发出请求,使用用法如下, 我们可以根据自己接口的实际情况,编写相对应的单元测试代码,检查我们的接口是否正常返回

from django.test import Client
c = Client()
response = c.post('/login/', {'username': 'john', 'password': 'smith'})
print(response.status_code)
response = c.get('/customer/details/')

在运行的时候,我们不在单独运行test文件,而是通过django的命令去启动测试 python manage.py test [app name] ,启动的时候,会根据已有的model 去创建新的test数据库,也就是说整个测试数据库初始的时候是空的,并且整个测试run完,数据库会被摧毁。
Tips:

  • 在django的单元测试中,每次测试用例执行完,都会恢复数据库,所以我们如果在一个用例中,修改了某个model的值,并不会影响后面的使用。
  • 有时候,我们期望的是在一个有数据的数据库里执行我们的测试,所以,我们可以加上 --keepdb 选项,这样在每次运行完之后, 数据库已有的数据还是存在的。
  • 我们希望跑单元测试的数据库是单独的一个,和线上分离,所以需要在数据库配置(settings.py 文件中) 指定

    DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': '',
        'USER': '',
        'HOST':'',
        'PASSWORD': '',
        'PORT': '',
        'TEST': {# 配置对应的测试数据库
            'NAME': 'mdw_pre', 
        }
    }
    }
    
  • 在运行过程中,可能会打印出一些项目的log 记录, 我们可以通过

-v {0,1,2,3}, —verbosity {0,1,2,3}
Verbosity level; 0=minimal output, 1=normal output,
2=verbose output, 3=very verbose output
```

  • 至此,我们可以比较完整的编写我们自己项目单元测试了

单元测试API

测试模板类

  Django框架为使用者提供了四种的测试模板,分别为TestCase、LiveServerTestCase、TransactionTestCase、SimpleTestCase。其中SimpleTestCase是Django框架中最基本的模板类是在unittest.TestCase类基础上增加了部分功能构造的子类。在没有数据库操作时可使用该类作为测试模板。TransactionCase和TestCase在此基础之上支持复杂的数据库操作。一般情况下使用TestCase作为测试模板类。
  在模板类中,除用于测试的样例方法之外,使用者还可以重构框架提供的了几种特殊的方法,用于做一些数据准备和销毁的操作

Function Name Info
setUpClass 在每个测试类建立时会被调用
tearDownClass 在运行完测试类中每个样例后被调用
setUp 在执行每个测试样例前被调用
tearDown 在执行完每个测试样例后被调用
setUpTestData TestCase类的方法,类似于setUpClass,执行更快速

请求的发送

  在Django.test模块中定义了Client类用于在测试工程中模拟多种请求的发送。通过使用Client的对象中的不同方法并对相应的参数进行设置便能够使用单元测试的请求发送功能。并且需要调用的方法与需要发送的请求有相同的名称,比如发送Get请求时需要调用Client.get方法。

# 引入客户端模拟类
from Django.test import Client
# 创建客户端模拟对象
c = Client()
# 客户端发送请求
c.get('url')

  Django的单元测试模板类继承了CLient类。能够在构造单元测试类中直接调用Client类的相应方法。

from Django.test import TestCase
class TestUnit(TestCase):
    def test(self):
        # 调用自身的方法
        self.get('url')
        pass

Django支持的请求类型

  Django测试模块支持以下类型的请求。

请求类型 调用方法
Post请求 post(path, data=None, content_type=MULTIPART_CONTENT, follow=False, secure=False, **extra)
Get请求 get(path, data=None, follow=False, secure=False, **extra)
Head请求 head(path, data=None, follow=False, secure=False, **extra)
Option请求 options(path, data=’’, content_type=’application/octet-stream’, follow=False, secure=False, **extra)
Put请求 put(path, data=’’, content_type=’application/octet-stream’, follow=False, secure=False, **extra)
Patch请求 patch(path, data=’’, content_type=’application/octet-stream’, follow=False, secure=False, **extra)
Delete请求 delete(path, data=’’, content_type=’application/octet-stream’, follow=False, secure=False, **extra)
Trace请求 trace(path, follow=False, secure=False, **extra)

常用参数含义
参数名 含义解释
path 发送请求使用url
data 发送请求时携带的数据
content_type 携带数据的格式

请求数据的接收与处理

  通过Client对象发出的请求在经过被测试单元的一系列操作之后,返回的数据会以返回值的形式返回。一般情况下,后端返回的数据形式为json格式,在接收数据后需要调用json方法进行解析。

c = Client()
response = c.get('/res/')
renponse = response.json()
# 此时response为字典格式的数据

结果的验证

  同其他单元测试类似,Django框架提供了几种断言函数,用于对运行结果进行验证,并且每个模板类都包含了这些函数。

class TestUnit(TestCase):
    def test(self):
        self.assertEqual(a, b) # 检验a是否等于b
        self.assertTrue(a)
        self.assertFalse(b)
        # ......

  更多的断言函数见官方模板的相应部分


单元测试的运行

运行单元测试

  在Terminal中输入以下指令即可运行单元测试文件。其中Module_name为需要运行的模块的名称。

py manage.py test Module_name

覆盖率的统计

  笔者开发使用的IDE是PyCharm,其中自带覆盖率统计插件。以run with coverage的方式运行单元测试能够自动地获取到被测试单元的覆盖率。


参考资料