在Node.js中为Restful API编写单元测试
作者:Scarletsky 发布时间:[ 2017/1/18 15:18:24 ] 推荐标签:软件测试 单元测试
单元测试是针对程序模块来进行正确性检验的测试工作,程序单元是应用的小可测试部件。
在 Web 应用中,我们可以把 Restful API 看作是构成应用的单元。
Restful API 比较好测试,测试起来也比较简单。
本文将介绍编写测试的原因和原则,然后以 Node.js 为例子介绍测试 Restful API 的方法。
为什么要编写测试
每个开发者都知道单元测试的重要性,但并不是每个开发者都会去编写单元测试。原因也很容易理解:
· 编写测试需要更多的时间,会拖慢项目进度
· 编写测试需要写更多的代码,更容易出现错误
· 当需求更变后,我们要花更多的精力去修改测试代码
· 有时候测试代码可能会比源代码多几倍
我以前也抱有类似的想法,认为人工测试足够了,没必要特意去编写单元测试。
然而随着项目的规模的增大,代码也会慢慢出现意外。
典型的例子是为了某需求修改了 A 位置,需求完成了,而 B 位置出现了 Bug。
在读过 王垠大神的《测试的道理》 之后,我更加明白了一个道理:我没有大神般的编码能力,我只能通过单元测试来检验自己的编码。
除了检验代码的正确性之外,我认为单元测试还有一个很重要的作用:为日后重构项目做准备。
只要单元测试覆盖得够好,以后重构的时候很容易发现问题,节约大量的时间。
轮子哥在 知乎 上说过一句很有意思的话:
所以那些专门写不需要维护的软件的人,讨厌测试,也是情有可原的。
如果你要编写一个长期维护的软件,那么你好添加单元测试。
F.I.R.S.T 原则
当我们决定要编写单元测试之后,我们要考虑怎样 写好 单元测试,换句话说是编写单元测试时需要注意哪些原则。
那么,有哪些原则是我们需要注意的呢?
· Fast : 测试必须是快速的
· Isolated / Independent :
每个测试都要做 3 A => Arrange(准备), Act(行动), Assert(断言)
Arrange: 测试过程中用到的数据不能依赖于运行环境,测试中用到的数据应是测试中的一部分
Act: 调用你想要测试的方法 / API
Assert: 根据返回结果进行断言
测试结果不能依赖运行环境
测试结果不依赖运行测试的顺序
· Repeatable :
每个测试必须是可重复执行的,即运行 N 次,会得到 N 次相同的结果
每个测试的结果不应依赖时间,日期,和随机数的输出
· Self-validating :
每个测试都可以自己判断结果来判断测试是否通过
不需要人类去查阅手册来判断结果
· Thorough and Timely :
应该尽量覆盖所有使用场景
应该尝试测试驱动开发(TDD)
这是经典的 F.I.R.S.T 原则。
我们好时刻注意自己编写的单元测试是否遵守这些原则。
JavaScript 社区里有很多测试框架可以用来编写单元测试,有 ava 、 mocha 、 jasmine 、 tap 等。
这些测试框架都有提供 beforeEach 、 afterEach API,目的是隔离我们的测试数据,从而满足 Isolated / Independent 和 Repeatable 原则。
编写单元测试
假设我们有以下 Restful API (用了 jwt 来做用户验证):
const router = new Router()
// 根据 token 获取用户信息,必须登录
router.get('/user', jwt, user.getSelf)
// 获取用户列表,无需登录
router.get('/users', user.getList)
// 获取指定用户信息,无需登录
router.get('/users/:userId', user.get)
// 创建新用户(用户注册),无需登录
router.post('/users', user.create)
// 更新用户信息,必须登录
router.put('/user', jwt, user.update)
那么我们应该怎样为这些 Restful API 编写单元测试呢?
基本流程是:
· 为 app 创建 http 服务器
· 对各个 API 发出请求
· 对响应内容进行断言
幸运的是,社区里已经有相应的工具让我们可以方便管理这个流程,这个工具是 —— supertest 。
它提供了非常灵活的 API,足以帮助我们测试 Restful API 了。
基本用法如下:
const app = require('../app')
const request = require('supertest')(app)
request
.get('/users')
.expect(200)
.end((err, res) => {
res.body.should.be.an.Array()
})
提示
如果你遇到了 TypeError: app.address is not a function , 请尝试一下以下方法:
const request = require('supertest').agent(app.listen())
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11