Django的单元测试和集成测试
测试,在以前确实是经常被忽略的话题,特别是对于 Python Web 这种快速开发框架
目录8 个章节
前言
好久没搞 Django 了,最近维护一个我之前用 Django 开发的项目竟然有亲切的感觉😂
测试,在以前确实是经常被忽略的话题,特别是对于 Python Web 这种快速开发框架,怎么敏捷怎么来,快速开发快速上线,而不是慢工出细活做得很规范,往往也是因为这种粗狂的开发风格,导致项目后续难以维护,这时候再给 Python 冠上一个开发容易维护难的名字。
Python: 我不背这锅😒
说回正题,这次的测试包括两部分,在 Django 项目内部写单元测试和集成测试,保证项目功能正常,然后我还开发了一个独立的自动测试工具,可以根据 OpenAPI 的文档来测试,并且在测试完成后输出测试报告,报告内容包括每个接口是否测试通过和响应时间等。
这个工具我使用了 go 语言开发,主要是考虑到了 go 语言可以傻瓜式的实现交叉编译,生成的可执行文件直接上传到服务器就可以执行,非常方便。
这个自动测试工具我会在下一篇文件介绍。
Django 的测试
不得不说 Django 的文档写得真不错👍
我看了一会文档就开始写测试,Django 全家桶真的舒服,开发体验太丝滑了
使用 startapp 创建 app 的时候,每个 app 目录下都有个 tests.py 文件,我们的测试代码就写在这个文件里面好了。
如果测试代码很多的话,还可以拆分,如何拆分参考 views.py 的拆分,把 tests.py 改成 package ,即创建个 tests 目录,下面放各个测试文件,然后在 __init__.py 里引入。
测试分为单元测试和集成测试,在 Django 里写单元测试比 AspNetCore 舒服多了,不用考虑依赖注入的问题,Django 全给你处理好了。
在测试的时候,Django 会自动创建测试数据库,因此也不用自己去折腾环境隔离啥的。
关于这俩种测试的区别,我之前的文章里有介绍,就不复制粘贴了。
例子
这次以两个 app 为例
- config - 单元测试
- dashboard - 集成测试
在 Django 里这俩种测试都没啥心智负担,也不用啥额外的操作,直接在 tests.py 里写就完事了。
单元测试
以 config app 作为单元测试的例子
我封装了一个 ConfigService 代码如下
from datetime import date
from .models import CommonConfig
class ConfigService(object):
def __init__(self):
...
@staticmethod
def get_config(key: str) -> str:
queryset = CommonConfig.objects.filter(key=key)
if queryset.exists():
return queryset.first().value
return ''
@property
def today(self):
return date.today()
@property
def start_year(self):
value = self.get_config('start_year')
return str(self.today.year) if len(value) == 0 else value
@property
def start_month(self):
value = self.get_config('start_month')
return str(self.today.month) if len(value) == 0 else value
@property
def end_year(self):
value = self.get_config('end_year')
return str(self.today.year) if len(value) == 0 else value
@property
def end_month(self):
value = self.get_config('end_month')
return str(self.today.month) if len(value) == 0 else value
编辑 apps/config/tests.py
from django.test import TestCase
from apps.config.models import CommonConfig
from apps.config.services import ConfigService
class CommonConfigTestCase(TestCase):
def setUp(self):
CommonConfig.objects.create(key='start_year', value='2023')
CommonConfig.objects.create(key='end_year', value='2024')
CommonConfig.objects.create(key='start_month', value='1')
CommonConfig.objects.create(key='end_month', value='10')
def test_common_config(self):
cfg = ConfigService()
self.assertEqual(cfg.start_year, '2023')
self.assertEqual(cfg.end_year, '2024')
self.assertEqual(cfg.start_month, '1')
self.assertEqual(cfg.end_month, '10')
集成测试
集成测试是模拟 HTTP 请求去访问接口,看看接口正不正常。
Django 的 TestCase 类里自带了 client 属性,可以很方便的请求接口。
一般接口都要登录才能用,然后 client 里也很贴心的集成了 Django 的认证授权体系,直接 login 就完事了。
注意测试的时候是自动创建了临时数据库,所以得先添加用户。
接着调用 self.client.get, self.client.post 之类的方法去测试接口就好了。
from django.test import TestCase
from django.shortcuts import reverse
from django.contrib.auth.models import User
from rest_framework import status
class DashboardTests(TestCase):
def setUp(self):
User.objects.create_user(username='user', password='pwd')
self.client.login(username="user", password="pwd")
def test_overview(self):
resp = self.client.get(reverse('dashboard:overview'), {'grant_year': 2023, 'grant_month': 2})
self.assertEqual(resp.status_code, status.HTTP_200_OK)
self.assertEqual(resp.json()['code'], status.HTTP_200_OK)
def test_monthly_data(self):
resp = self.client.get(reverse('dashboard:monthly_data'), {'grant_year': 2023, 'grant_month': 2})
self.assertEqual(resp.status_code, status.HTTP_200_OK)
self.assertEqual(resp.json()['code'], status.HTTP_200_OK)
def test_county_data(self):
resp = self.client.get(reverse('dashboard:county_data'), {'grant_year': 2023, 'grant_month': 2})
self.assertEqual(resp.status_code, status.HTTP_200_OK)
self.assertEqual(resp.json()['code'], status.HTTP_200_OK)
运行测试
测试写完之后
使用命令运行测试
python manage.py test
还有其他参数请参考官方文档
不过运行测试的时候就没有 AspNetCore 爽了,没有那种一个个接口相继亮起绿灯的快感;
Django 的测试只能看到测试结果,有多少个测试通过了,如果有报错会看到 Traceback 信息。
$ python .\manage.py test
Found 5 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.....
----------------------------------------------------------------------
Ran 5 tests in 0.831s
OK
Destroying test database for alias 'default'...
小结
Django 还是熟悉的味道,好用就对了。
参考资料
没想到不知不觉中 Django 刷版本号到 5.0 了…
_EOF_
Django的单元测试和集成测试
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
分享一些2026年有意思的现代化Django生态组件
2026年了,若还在忍受石器时代的模板和冗余CRUD,趁早转行。Cotton和Inertia总算给Django这老古董续了命,Ninja这类工具已是开发及格线。看一眼这些现代化组件吧,别再用那些自我感动的低效代码来折磨审美了。
2026-01-21 · Django · 约 1 分钟
Django项目引入NPM和gulp管理前端资源
前言 之前写了一篇《Asp-Net-Core开发笔记:使用NPM和gulp管理前端静态文件》,现在又来用Django开发项目了,之前我搞了一个Django的快速开发脚手架「DjangoStarter」,正好给升级一下~ 关于npm和gulp我就不多重复了,之前那篇文章都写了,直接上操作 安装依赖 安装依赖的操作跟上一篇文章是一样的,不过我这里直接提供package.json文件,复制到项目根目录里
2022-04-02 · Django · 约 1 分钟
轻松搞定Django分页功能
view代码 from django.core.paginator import Paginator def announcement(request): ctx = { 'global': GlobalCtx, 'announcements': models.Announcement.objects.all(), } paginator
2022-05-27 · Django · 约 1 分钟
比Django官方实现更好的分页组件+Bootstrap整合
前言 Django全家桶自带的分页组件只能说能满足分页这个功能,但是没那么好用就是了 Django的分页效果 django-pure-pagination分页效果 使用方法 首先安装: pip install django-pure-pagination 添加到App INSTALLED_APPS = ( ... 'pure_pagination', ) 配置一下,配置说明如图 P
2021-12-18 · Django · 约 1 分钟
讨论
共 0 条加载评论中…