前言

好久没搞 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 会自动创建测试数据库,因此也不用自己去折腾环境隔离啥的。

关于这俩种测试的区别,我之前的文章里有介绍,就不复制粘贴了。

Asp-Net-Core学习笔记:单元测试和集成测试

例子

这次以两个 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 了…

Python项目维护不了?可能是测试没到位。Django的单元测试和集成测试初探的更多相关文章

  1. Python项目在Jenkins中的自动化测试实践(语法检查、单元测试,coverage(代码覆盖率)、自动打包)

    原始链接:http://blog.csdn.net/a464057216/article/details/52934077 requirments OS: Ubuntu 14.04+ Gitlab 8 ...

  2. 正确地组织python项目的结构

    统一的项目结构 写了不少python项目后, 越来越认识到python项目结构重要性. 不管项目是否要开源, 是否要提交pypi, 项目结构的一致性带来的好处还有很多: 多人合作开发大家都有个基本的g ...

  3. 以正确的方式开源 Python 项目

    以正确的方式开源 Python 项目 大多数Python开发者至少都写过一个像工具.脚本.库或框架等对其他人也有用的工具.我写这篇文章的目的是让现有Python代码的开源过程尽可能清 晰和无痛.我不是 ...

  4. 创建成功的Python项目

    创建成功的Python项目 前端开发工具技巧介绍—Sublime篇 SEO在网页制作中的应用 观察者模式 使用D3制作图表 英文原文:Create successful Python projects ...

  5. 以正确的方式开源 Python 项目(转)

    大多数Python开发者至少都写过一个像工具.脚本.库或框架等对其他人也有用的工具.我写这篇文章的目的是让现有Python代码的开源过程尽可能清晰和无痛.我不是简单的指——“创建一个GitHub库,提 ...

  6. Docker如何部署Python项目

    Docker 部署Python项目 作者:白宁超 2019年5月24日09:09:00 导读: 软件开发最大的麻烦事之一就是环境配置,操作系统设置,各种库和组件的安装.只有它们都正确,软件才能运行.如 ...

  7. 笔记14:Docker 部署Python项目

    Docker 部署Python项目 导读: 软件开发最大的麻烦事之一就是环境配置,操作系统设置,各种库和组件的安装.只有它们都正确,软件才能运行.如果从一种操作系统里面运行另一种操作系统,通常我们采取 ...

  8. 如何建立一个完美的 Python 项目

    原文地址:How to set up a perfect Python project 原文作者:Brendan Maginnis 译者:HelloGitHub-丫丫 校对者:HelloGitHub- ...

  9. Python开发入门与实战11-单元测试

    11. 单元测试 本章节我们来讲讲django工程中如何实现单元测试,单元测试如何编写以及在可持续项目中单元测试的重要性. 下面是单元测试的定义: 单元测试是开发者编写的一小段代码,用于检验被测代码的 ...

  10. 使用 tox flake8 pytest 规范 python 项目

    使用 tox flake8 pytest 规范 python 项目 python 中有些很好的工作来规范整个项目的开发,而其中使用较多的就是使用 tox . flake8 . pytest . tox ...

随机推荐

  1. CF676C 题解

    使用尺取法(双指针法). 由于字符种类只有 \(2\) 种,答案一定是全 a 或全 b. 情况 \(1\):全 a 快指针循环移动,并统计字符 b 的数量 \(cntb\),直到 \(cntb\) 即 ...

  2. 深度学习基础入门篇[二]:机器学习常用评估指标:AUC、mAP、IS、FID、Perplexity、BLEU、ROUGE等详解

    A.深度学习基础入门篇[二]:机器学习常用评估指标:AUC.mAP.IS.FID.Perplexity.BLEU.ROUGE等详解 1.基础指标简介 机器学习的评价指标有精度.精确率.召回率.P-R曲 ...

  3. 5.11 汇编语言:仿写IF条件语句

    条件语句,也称为IF-ELSE语句,是计算机编程中的一种基本控制结构.它允许程序根据条件的真假来执行不同的代码块.条件语句在处理决策和分支逻辑时非常有用.一般来说,条件语句由IF关键字.一个条件表达式 ...

  4. NetCat 工具的常用使用技巧

    netcat 黑客们的瑞士军刀,虽然小巧但是其功能一点也不弱,并且该工具天生免杀,值得你去尝试. NCwindows反弹 1:正向连接 服务器执行:nc -l -p 8888 -e cmd.exe 本 ...

  5. CF351D Jeff and Removing Periods 题解

    题目链接:CF 或者 洛谷 挺有意思的题,一开始看到了 \(start+k\times step\),以为是根号分治方向的题,结果发现这题还给了一个"重排"操作玩玩.所以这题其实算 ...

  6. CF763E Timofey and our friends animals题解

    题目链接:CF 或者 洛谷 简单来说就是求 \([l,r]\) 这些点都存在的情况下,连通块的数量,看到七秒时限,而且每个点相连的边数很少,可以想到离线下来使用莫队类的算法解决 连通块问题,一般可以考 ...

  7. 小知识:grep过滤以#号开头的注释行 和 空行

    xtts的配置文件,有很多注释不想直接去掉的情况下,想清楚的看到目前设置了哪些参数,可以用grep过滤查看: grep -vE '^#|^$' xtt.properties 效果如下: [oracle ...

  8. CF1850H The Third Letter

    题目链接 题解 知识点:贪心,图论建模. 考虑对约束 a b d 建边 \(a \mathop{\to}\limits^d b\) 与 \(b \mathop{\to}\limits^{-d} a\) ...

  9. NC24734 [USACO 2010 Mar G]Great Cow Gathering

    题目链接 题目 题目描述 Bessie is planning the annual Great Cow Gathering for cows all across the country and, ...

  10. NC24870 [USACO 2009 Dec G]Video Game Troubles

    题目链接 题目 题目描述 Farmer John's cows love their video games! FJ noticed that after playing these games th ...