单元测试的好处
-
代码质量持续有保障
-
重构正确性保障
-
增强自信心
-
自动化运行
对于应用的 Controller、Service、Helper、Extend 等代码,都必须有对应的单元测试保证代码质量
测试框架
-
Mocha
-
AVA
断言库
power-assert
测试约定
测试目录结构
约定 test
目录为存放所有测试脚本的目录。
测试脚本文件统一按 ${filename}.test.js
命名(注意:必须以 .test.js
作为文件后缀)。
测试运行工具
使用egg-bin
来运行测试脚本(它会自动将内置的 Mocha
、co-mocha
、power-assert
,nyc
等模块组合引入到测试脚本中)
-
配置
在
package.json
上配置好scripts.test
{
"scripts": {
"test": "egg-bin test"
}
}
- 运行测试
npm test
准备测试
mock
app
测试前,创建应用的一个app
实例,来访问需要被测试的Controller
、Middleware
、Service
// test/controller/home.test.js
const { app, mock, assert } = require('egg-mock/bootstrap');
describe('test/controller/home.test.js', () => {
// test cases
});
ctx
结合 egg-mock 提供的 app.mockContext(options)
方法来快速创建一个 ctx 实例
const ctx = app.mockContext();
测试执行顺序
Mocha
使用 before/after/beforeEach/afterEach
来处理前置后置任务,基本能处理所有问题。 每个用例会按 before
-> beforeEach
-> it
-> afterEach
-> after
的顺序执行,而且可以定义多个
异步测试
egg-bin
支持测试异步调用,支持多种写法:
-
使用返回
Promise
的方式 -
使用
callback
的方式 -
使用
async
Controller
测试·
Controller
跟router
配置紧密相关,需要利用app.httpRequest()
SuperTest发起一个真实请求,来将Router
和Controller
连接起来,并且可以帮助我们发送各种满足边界条件的请求数据, 以测试 Controller 的参数校验完整性。app.httpRequest()
是 egg-mock 封装的 SuperTest 请求实例。
app.httpRequest()
可以发送GET
、POST
、PUT
等HTTP请求
mock CSRF
框架的默认安全插件会自动开启 CSRF 防护。
egg-mock 对 app 增加了 app.mockCsrf()
方法来模拟取 CSRF token 的过程。 这样在使用 SuperTest 请求 app 就会自动通过 CSRF 校验。
Service
测试
需要先创建一个 ctx,然后通过 ctx.service.${serviceName}
拿到 Service 实例, 然后调用 Service 方法即可。
Extend
测试
应用可以对 Application、Request、Response、Context 和 Helper 进行扩展。我们针对性的编写单元测试
Application
egg-mock 创建 app 的时候,已经将 Application 的扩展自动加载到 app 实例了, 直接使用这个 app 实例访问扩展的属性和方法即可进行测试。
Context
Context 测试只比 Application 多了一个 app.mockContext()
步骤来模拟创建一个 Context 对象。
Request
通过 ctx.request
来访问 Request 扩展的属性和方法,直接即可进行测试。
Response
通过 ctx.response
来访问 Response 扩展的属性和方法,直接即可进行测试。
Helper
通过 ctx 来访问到 Helper,然后调用 Helper 方法测试。(ctx.helper
)
Mock
方法
egg-mock
提供了非常多的mock
方法
-
不想在终端 console 输出任何日志,可以通过
mock.consoleLevel('NONE')
来模拟 -
想模拟一次请求的 Session 数据,可以通过
app.mockSession(data)
来模拟
mock
之后会一直生效,为了避免每个单元测试用例之间不相互mock
污染,通常我们都会在 afterEach
钩子里面还原掉所有 mock
describe('some test', () => {
// before hook
afterEach(mock.restore);
// it tests
});
引入 egg-mock/bootstrap 时,会自动在 afterEach 钩子中还原所有的 mock,不需要在测试文件中再次编写
网友评论