其他测试框架 [腾讯 TMQ] Jest 基本使用方法以及 mock 技巧介绍

匿名 · 2018年07月20日 · 1852 次阅读

导读

Jest 是由 Facebook 开发并维护的一套 js 的单元测试框架,之前在后台的 nodejs 项目里面第一次尝试使用,感觉还是非常容易上手的,功能也比较强大。尤其是 mock 方面也别好用,还天然的支持覆盖率,所以非常推荐使用。

内置支持的功能如下:

  • 灵活的配置:比如,可以用文件名通配符来检测测试文件;

  • 测试的事前步骤 (Setup) 和事后步骤 (Teardown),同时也包括测试范围;

  • 匹配表达式 (Matchers):能使用期望 expect 句法来验证不同的内容;

  • 测试异步代码:支持承诺 (promise) 数据类型和异步等待 async / await 功能;

  • 模拟函数:可以修改或监查某个函数的行为;

  • 手动模拟:测试代码时可以忽略模块的依存关系;

  • 虚拟计时:帮助控制时间推移。

1 基本使用介绍

1.1 安装

1.2 一个简单的例子

被测试文件:sum.js

测试文件: sum.test.js

将下面的配置部分添加到你的 package.json 里面:

"scripts": {
"test": "jest"
}

执行下面的命令即可:

npm test

结果:

注意:jest 会自动搜索路径下面所有 test.js 结尾的文件, 默认都会执行。

如果想单独运行某个测试文件可以直接加上文件名就可以。

如上面的例子可以:

npm test sum.test.js 或者 jest sum.test.js
也可以在 jest 配置文件里配置上 testRegex
testRegex 默认值:(/tests/.*|(\.|/)(test|spec))\.jsx?$

1.3 Jest 配置选项

可以参考:
https://facebook.github.io/jest/docs/en/configuration.htmlcollectCoverage里面,比较有用的就是 默认是 false,设置成 true 的话执行完测试就会自动统计覆盖率。

如图:

1.4 jest 命令行

除了用 npm test 执行测试,也可以直接 jest 执行所有用例,jest 支持的命令行参数可以参考:
https://facebook.github.io/jest/docs/zh-Hans/cli.html
命令行参数仅支持 jest 执行,npm test 这样是不支持命令行的。

下面介绍比较常用的:

(1)——runInBand

jest --runInBand

可以顺序执行所有用例,默认所有用例是并行执行的。

(2)——debug

执行前打印 jest 所有配置信息。 

2 Jest 的 mock 技巧介绍

2.1 基本的 mock

2.1.1 Mock 一个函数

方法的 mock 非常简单,使用 jest.fn 就可以非常简单的 mock 一个函数。
如下面的例子:代码里面有一个函数叫 forEach。

此函数可以简单使用下面方法 mock,并且 jest 提供一些方法可以确保查看 mock 函数被调用的情况:

mock 属性的所有 api 可以参考:https://facebook.github.io/jest/docs/en/mock-function-api.html

2.1.2 Mock 返回值

可以使用 mock 注入返回值,可以使用的 api 为 mockReturnValue,mockReturnValueOnce 等。

如下面的例子:

2.1.3 Mock 内部实现

使用 jest.fn 或者 mockImplementationOnce 可以完全替换需要 mock 的函数。

如下面的例子:

当需要 mock 的函数是从其他模块创建的就可以使用 mockImplementation。

2.1.4 Mock 名字

可以使用 mockName 来给 mock 函数命名,如果没有命名,输出的日志默认就会打印 jest.fn(),加上名字更有利于调试。

另外有用的 mock 方法可以参考:
https://facebook.github.io/jest/docs/en/mock-functions.html

2.2 模块的 mock

这里面有几种方式来 mock:

2.2.1 使用 jest.mock 自动 mock

2.2.2 jest.mock() 直接在单元测试里面 mock 模块

例如我们很多产品代码里面会使用 fs 文件读取文件, 在单元测试中, 我们并不需要真去调用 fs 读取文件, 就可以考虑把 fs 模块 mock 掉, 如下代码:

2.2.3 在需要 mock 的模块目录临近建立目录mocks
这里面分两种情况:

2.2.3.1 对于用户目录下面的模块

例如我们需要 mock 目录 models 下面的 user 模块,那么我们就需要在 models 下面新建mocks目录(这里要区分大小写),然后新建文件 user.js。

注意:用这种方式, 需要在单元测试文件中需添加下面的代码才能使此 mock 生效。

2.2.3.2 对于 node_modules 下面的模块

如果我们需要 mock 的模块是一个 Node 的模块(如 lodash
),那么 mocks应该是挨着 node_modules 目录(除非你手动配置的 roots 指向非本项目的 root 目录),这种就会自动 mock 了,也就是不需要在单元测试用例里再调用 jest.mock('module_name')。

如果需要 mock 的模块是 scoped 模块,那么我们创建的 mock 的名字需要一致,例如, mock 模块名字为 @scope/project-name,那么就需要创建mocks/@scope/project-name.js。

注意:如果我们需要 mock node 的核心模块(如 fs 或者 path),那么还是需要显示的调用 jest.mock('path') , 因为核心的 node 模块默然是不被 mock 的。

总结一下上面两种 mock 的目录应该如下:

2.3 类的 mock

类可以用四种方式来 mock 一个类。

此部分我们使用下面的类来举例:

使用下列用例 check 下 mock 的执行情况:

2.3.1 jest.mock 自动 mock 类所在的模块, 类和类的方法也自动被 mock。

2.3.2 在mock_路径建立 mock 的文件:

2.3.3 使用带模块工厂参数的 mock。

形式如下 jest.mock(path, moduleFactory),其中模板工厂参数指的是一个返回模块的函数

2.3.4. 使用 mockImplementation() 或者 mockImplementationOnce() 代替 mock

可以使用 mockImplementation() (or mockImplementationOnce()) 代替上面的带模板工厂参数的 mock 方法,mockImplementation 或者 mockImplementationOnce 来修改 mock。

如下面的例子,在使用了 mock 之后,随时可以使用。

可以参考:
https://facebook.github.io/jest/docs/en/es6-class-mocks.html

总结

对于简单的函数的 mock,推荐使用 jest.fn 来进行 mock,针对不同的情况(例如返回值或者替换实现),可以考虑使用 mockReturnValue 和 mockImplementation;针对类和模块的 mock,推荐使用自动的 mock 方法也就是 jest.mock。对于比较复杂的类和接口,如果自动 mock 不能完成覆盖到的话,建议结合使用 jest.mock 和 jest.fn().mockImplementation,或者可以使用 jest.mock 完全自己 mock。

另外,jest 里面有 timer 的 mock,使用 jest.useFakeTimers() 可以自动 mock 代码里面的 setTimeout 和 setInterval 等函数具体信息请参考:
https://facebook.github.io/jest/docs/en/timer-mocks.html

关注腾讯移动品质中心 TMQ,获取更多测试干货!

版权所属,禁止转载!!!

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册