【Mocha.js 101】钩子函数

时间:2022-12-14 18:40:16

【Mocha.js 101】钩子函数

前情提要

在上一篇文章《【Mocha.js 101】同步、异步与 Promise》中,我们学会了如何对同步方法、异步回调方法以及 Promise 进行测试。

在本篇文章中,我们将了解到 Mocha.js 的「钩子函数」(Hooks)。

钩子(Hooks)

在测试过程中,我们经常会需要准备一些「桩数据」。集成测试中,通常会选择批量导入一部分模拟数据,或者同步一小部分线上数据,用于测试环境。

在单元测试中,往往需要在执行测试前,准备相关桩数据,并在测试后将其恢复原样。这便用到了钩子函数。

Mocha.js 提供了四中钩子函数,分别是 before() , after() , beforeEach() , afterEach() 。

  • before()  将会在所有测试用例执行之前运行,用于同一的桩数据导入等功能;
  • after()  则会在所有测试执行之后运行,用于清理测试环境,删除或回滚相关数据;
  • beforeEach()  将会在每个测试用例执行前执行,可以用于准备测试用例所需的前置条件;
  • afterEach()  将会在每个测试用例之后执行,可以用于准备测试用例所需的后置条件。

下面,我们来模拟一个场景。首先创建模拟业务逻辑,创建 src/chapter2/User.js 文件,并加入如下代码:

var stubDB = {};

/**
* 定义用户类
*
* @param name 用户名称
* @constructor
*/
function User( name ) {
} /**
* 保存用户.
*
* @param name 待保存的用户名称
*/
User.save = function ( name ) {
stubDB[ name ] = name;
}; /**
* 删除用户.
*
* @param name 待删除的用户名称
*/
User.delete = function ( name ) {
delete stubDB[ name ];
}; /**
* 检查是否包含该用户.
*
* @param name 待检查的用户名称
* @returns {boolean} 如果包含则返回 true, 否则返回 false
*/
User.contains = function ( name ) {
return stubDB[ name ] != null;
}; // Export the User class.
module.exports = User;

如代码所示,User  类提供了三个方法,save  用于保存用户,delete  用于删除用户,contains  用于判断用户是否存在。

接下来,让我们创建 test/chapter2/hooks.js  文件,并加入测试代码:

var should = require( 'should' );
var User = require( '../../src/chapter2/User' ); // 描述 User 行为
describe( 'User', function () { // 在执行所有测试前, 执行 before(), 添加桩数据
before( function () {
User.save( 'luochuan' );
} ); // 在执行每个测试前, 执行 beforeEach(), 添加桩数据
beforeEach( function () {
User.save( 'hermit' );
} ); // 描述 User.save 行为
describe( '#save', function () { // 保存 robert 用户成功.
it( 'Save "robert" successfully.', function () {
User.save( 'robert' );
} );
} ); // 描述 User.contains 行为
describe( '#contains', function () { // 应该存在 Hermit 用户
it( '"Hermit" already exists.', function () {
User.contains( 'hermit' ).should.be.exactly( true );
} ); // 应该不存在 Martin 用户
it( '"Martin" not exists.', function () {
User.contains( 'Martin' ).should.be.exactly( false );
} );
} ); // 在执行完每个测试后, 清空桩数据.
afterEach( function () {
User.delete( 'hermit' );
} ); // 在执行完每个测试后, 清空桩数据.
after( function () {
User.delete( 'luochuan' );
} );
} );

测试代码中,我们定义了 before() ,after() ,beforeEach()  和 afterEach() 。接下来,我们来执行测试,看看输出结果:

$ mocha test/chapter2/hooks.js

  User
#save
✓ Save "robert" successfully.
#contains
✓ "Hermit" already exists.
✓ "Martin" not exists. 3 passing (9ms)

我们将会发现,测试三个测试均已通过。所以证明,相关钩子函数已经正确执行,并插入了我们需要的桩数据。

描述钩子函数

在之前的文章中,我们介绍了 describe()  函数。通过 describe()  函数,我们描述了对一个测试用例的预期。

同样,对于钩子函数,我们也能够添加相应的描述信息。

  • before( description, callback )
  • after( description, callback )
  • beforeEach( description, callback )
  • afterEach( description, callback )

我们只需要指定钩子函数的 description 参数,即可描述该行为。接下来,让我们创建 test/chapter2/describeHooks.js ,来试试描述钩子函数:

var should = require( 'should' );
var User = require( '../../src/chapter2/User' ); // 描述 User 行为
describe( 'User', function () { // 在执行所有测试前, 执行 before(), 添加桩数据
before( 'Before all tests.', function () {
User.save( 'hermit' );
} ); // 在执行每个测试前, 执行 beforeEach(), 添加桩数据
beforeEach( 'Before each test case.', function () {
} ); // 描述 User.save 行为
describe( '#delete', function () { // 删除 hermit 用户成功.
it( 'Delete user successfully.', function () {
User.delete( 'hermit' );
} );
} ); // 在执行完每个测试后, 清空桩数据.
afterEach( 'After each test case.', function () {
} ); // 在执行完每个测试后, 清空桩数据.
after( 'After all tests.', function () {
User.delete( 'hermit' );
} );
} );

如代码高亮处所示,我们为钩子函数添加了描述信息。

接下来,让我们执行测试:

$ mocha test/chapter2/describeHook.js

  User
#delete
✓ Delete user successfully. 1 passing (7ms)

做到这里,大家会感到很疑惑:和上面的输出并没有什么区别啊?

其实,描述信息是为了方便问题定位的。我们来模拟一下 beforeEach()  函数抛出异常的情况:

beforeEach( 'Before each test case.', function () {
throw Error();
} );

同样,我们执行测试:

$ mocha test/chapter2/describeHook.js

  User
#delete
1) "before each" hook: Before each test case. for "Delete user successfully." 0 passing (8ms)
1 failing 1) User "before each" hook: Before each test case. for "Delete user successfully.": rror
at Error (native)
at Context.<anonymous> (test/chapter2/describeHook.js:14:15)

这样,我们便看到,我们所定义的 beforeEach()  钩子执行失败。具体是 "before each" hook: Before each test case. for "Delete user successfully."

异步钩子函数

我们在上一篇文章中,介绍了异步测试的执行方式。钩子函数也同样支持异步执行,并且以相同的方法支持——done 参数。所以,在此我们利用上一篇文章的Ajax,做一个非常简单的示例:

describe( 'Ajax', function () {

    beforeEach( function ( done ) {
Ajax.load( 'url', function () {
done();
} );
} );
} );

Root钩子(Root-level Hooks)

将钩子函数写在 describe()  方法以外,将会作用于所有的测试用例。比如 beforeEach()  方法,如果写在了 describe()  方法以外,将会在所有的测试用例执行前执行该方法。

总结

本文介绍了 Mocha.js 如何使用钩子函数,模拟测试所需桩数据及模拟环境。Mocha.js 通过 before(),after(),beforeEach(),afterEach() 四个钩子函数,允许在测试用例前后执行相关代码。


本文以 CC BY-NC-SA 3.0 CN 协议共享,转载、共享及二次创作时请保留原文出处及链接,请勿用于商业用途。

本文链接:http://litecodes.com/dev/frontend/mocha-101-hooks/

Cnblogs 同步更新我的原始博客。

【Mocha.js 101】钩子函数的更多相关文章

  1. 【Mocha&period;js 101】同步、异步与 Promise

    前情提要 在上一篇文章<[Mocha.js 101]Mocha 入门指南>中,我们提到了如何用 Mocha.js 进行前端自动化测试,并做了几个简单的例子来体验 Mocha.js 给我们带 ...

  2. 【Mocha&period;js 101】Mocha 入门指南

    序 说到质量控制,不得不提起测试驱动开发(TDD)和行为驱动开发(BDD).随着敏捷软件开发的推行,软件质量控制的重担也逐渐从测试工程师转向了研发工程师.测试驱动也随之悄然而生,成为了敏捷开发中重要的 ...

  3. Vue2&period;0 探索之路——生命周期和钩子函数的一些理解 - JS那些事儿

    在使用vue一个多礼拜后,感觉现在还停留在初级阶段,虽然知道怎么和后端做数据交互,但是对于mounted这个挂载还不是很清楚的.放大之,对vue的生命周期不甚了解.只知道简单的使用,而不知道为什么,这 ...

  4. Node&period;js进阶篇-koa、钩子函数、websocket、嵌入式开发

    代码地址如下:http://www.demodashi.com/demo/12932.html 一.简介     koa是由Express原班人马打造的,致力于成为一个更小.更富有表现力.更健壮的We ...

  5. Atitit&period;跨平台预定义函数&&num;160&semi;魔术方法&&num;160&semi;魔术函数&&num;160&semi;钩子函数&&num;160&semi;api兼容性草案&&num;160&semi;v2&&num;160&semi;q216&&num;160&semi;&&num;160&semi;java&&num;160&semi;c&num;&&num;160&semi;php&&num;160&semi;js&period;docx

    Atitit.跨平台预定义函数 魔术方法 魔术函数 钩子函数 api兼容性草案 v2 q216  java c# php js.docx 1.1. 预定义函数 魔术方法 魔术函数是什么1 1.2. & ...

  6. js钩子函数实现一个简单动画

    <!DOCTYPE html> <html> <head> <title></title> <meta charset="u ...

  7. Vue&period;js 第2章 钩子函数&amp&semi;自定义指令&amp&semi;过滤器&amp&semi;计算属性&amp&semi;侦听器

    目标 钩子函数 自定义指令 自定义过滤器 计算属性 监听属性 局部自定义指令 为什么需要自定义指令 为了复用,为了代码的灵活 指令的分类:全局指令,局部指令 在vm外面创建的指令 通过Vue.dire ...

  8. 【js】vue 2&period;5&period;1 源码学习 (四) 钩子函数 资源选项 watch 的合并策略

    大体思路 (三)    1.钩子函数 自定义策略       LIFECYCLE_HOOKS= []      created = [function(){} , function(){}] 组装方法 ...

  9. Vue2&period;X的路由管理记录之 钩子函数(切割流水线)

    $route可以在子组件任何地方调用,代表当前路由对象,这个属性是只读的,里面的属性是 immutable(不可变) 的,不过你可以 watch(监测变化) 它. 导航和钩子函数: 导航:路由正在发生 ...

随机推荐

  1. 【微信Java开发 --2】接入微信公众平台开发,配置自己的服务器,验证过程

    接入微信公众平台开发,开发者需要按照如下步骤完成: 1.填写服务器配置 2.验证服务器地址的有效性 3.依据接口文档实现业务逻辑好我们就开始:1.填写好我们的URL和Token[此处是已经通过验证的] ...

  2. mysql之触发器入门

    触发器语法: CREATE TRIGGER <触发器名称>  --触发器必须有名字,最多64个字符,可能后面会附有分隔符.它和MySQL中其他对象的命名方式基本相象.{ BEFORE |  ...

  3. java模板和回调机制学习总结

    最近看spring的JDBCTemplete的模板方式调用时,对模板和回调产生了浓厚兴趣,查询了一些资料,做一些总结. 回调函数: 所谓回调,就是客户程序C调用服务程序S中的某个函数A,然后S又在某个 ...

  4. 【Android Studio 小技巧】一键查看文件方法结构目录File Structure

    看源代码的时候,如果可以查看class中的所有方法,可以提高效率.Android Studio 中可以使用快捷键一键显示所有方法的目录. Mac: command + fn + F12 (在mac中的 ...

  5. C&num;学习:集合、迭代、泛型(1)

    一.System.Collections名称空间下几个接口表征着集合的功能: 1.IEnumerable:表征着迭代功能 public interface IEnumerable { IEnumera ...

  6. Spring-demo1(初学者的尝试,2015&period;03&period;19)

    项目结构: 源代码如下: package com.bean; public interface Person { public void Speak(); } package com.bean; pu ...

  7. js点击 密码输入框密码显示隐藏

    很多密码框都有个眼睛标记,点击能显示密码.原理就是点击切换password为text等显示 下面上代码 <!DOCTYPE html> <html> <head> ...

  8. css定位 浮动 伪类 margin

    一,margin .标准文档流,margin在竖直方向的不叠加,以较大的为准 .使用margin: auto;的盒子必须有明确的width,并且只有标准文档流的盒子 才能使用margin: auto; ...

  9. Ubuntu版本更替所引发的&OpenCurlyDoubleQuote;血案”

    Ubuntu版本更替所引发的"血案"       今天,我兴致很高的装了双系统,并且配置了Linux的网络,接下来就是安装一些软件,来实现我想达到的功能了,结果被一个小小的命令卡的 ...

  10. Android开发者的Anko使用指南&lpar;二&rpar;之Dialogs

    在项目中使用Anko Dialogs dependencies { compile "org.jetbrains.anko:anko-commons:$anko_version" ...