11月阅读周·编写可测试的JavaScript代码:运行服务器端JavaScript单元测试篇

举报
叶一一 发表于 2024/11/22 11:29:45 2024/11/22
【摘要】 背景去年下半年,我在微信书架里加入了许多技术书籍,各种类别的都有,断断续续的读了一部分。没有计划的阅读,收效甚微。新年伊始,我准备尝试一下其他方式,比如阅读周。每月抽出1~2个非连续周,完整阅读一本书籍。这个“玩法”虽然常见且板正,但是有效,已经坚持阅读十个月。已读完书籍:《架构简洁之道》、《深入浅出的Node.js》、《你不知道的JavaScript(上卷)》、《你不知道的JavaScri...

背景

去年下半年,我在微信书架里加入了许多技术书籍,各种类别的都有,断断续续的读了一部分。

没有计划的阅读,收效甚微。

新年伊始,我准备尝试一下其他方式,比如阅读周。每月抽出1~2个非连续周,完整阅读一本书籍。

这个“玩法”虽然常见且板正,但是有效,已经坚持阅读十个月。

已读完书籍《架构简洁之道》、《深入浅出的Node.js》、《你不知道的JavaScript(上卷)》、《你不知道的JavaScript(中卷)》、《你不知道的JavaScript(下卷)》、《数据结构与算法JavaScript描述》、《WebKit技术内幕》、《前端架构:从入门到微前端》、《秒懂算法:用常识解读数据结构与算法》、《JavaScript权威指南》、《JavaScript异步编程设计快速响应的网络应用》

当前阅读周书籍编写可测试的JavaScript代码

运行服务器端JavaScript单元测试

服务器端JavaScript单元测试的过程,与其他服务器端代码的单元测试过程并没有太大的区别。测试和代码都驻留并运行在同一个主机上,这比客户端单元测试更简单。我将演示如何使用Jasmine进行服务器端JavaScript单元测试工作。

虽然可以编写自己的断言和测试框架,甚至也可以构建自己的飞机,但是不要白费力气做重复工作。如果不喜欢Jasmine,还有很多其他的测试框架可以使用,所以选择一个吧。

Jasmine

安装Jasmine非常简单:

npm install jasmine-node -g

Jasmine给我们提供了一个很好的方式,用命令行运行测试并以不同的方式输出测试结果:即人工或自动化方式。

其思想是,使用Jasmine语法和语义编写单元测试后,向Jasmine命令行指定这些测试所存放的根目录(或任意子目录)。Jasmine将遍历目录树,并运行所有找到的测试。

默认情况下,Jasmine期望测试文件中包含spec字符串,如sum-spec.js——该约定是BDD要件,可以使用--matchall选项进行重写。

如下是测试整数加法的Jasmine代码:

var mySum = require('./mySum');

describe('Sum', function () {
  it('Adds Integers! ', function () {
    expect(mySum.sum(7, 11)).toEqual(18);
  });
});

最后是运行上述测试的代码:

jasmine-node

Finished in 0.009 seconds
1 test, 1 assertion, 0 failures

测试通过了!我们当然知道,Jasmine匹配器(上述示例中的toEqual)等价于YUI Test的断言。另外,我们可以编写自己的自定义匹配器。Jasmine的describe相当于YUI Test的套件(suite),sepsc(it函数)类似于YUI Test的测试用例。Jasmine还支持用于在每个spec之前或之后执行的beforeEach和afterEach函数,其类似于YUI Test的 setUp和tearDown函数的测试。

依赖

对单元测试下的Node.js代码来说,生产其依赖对象是非常苛刻的,因为其依赖对象是通过require函数引入的。要做测试,需要修改源代码(不太好),或者模拟require函数本身(很痛苦)。幸运的是,对于后一种方法,已经有人为我们做了一个非常好的npm包,名称为Mockery。Mockery拦截所有的require调用,可以很容易地插入模拟版本的依赖对象,而不是真实对象。

如下是我们修改后的sum函数,该函数从文件中读取JSON字符串,查找其中的a和b属性,并将其进行相加:

var fs = require('fs');
exports.sum = function (file) {
  var data = json.parse(fs.readFileSync(file, 'utf8'));
  return data.a + data.b;
};

如下是对sum函数的Jasmine测试代码:

var mySum = require('./mySumFS');
describe('Sum suite File', function () {
  it('Adds Integers! ', function () {
    expect(mySum.sum('numbers')).toEqual(12);
  });
});

numbers文件的内容如下:

{'a':5, 'b':7}

很好——Jasmine运行该测试并通过,一切都很顺利。但我们同时测试的内容太多了——将fs依赖引入并利用,单元测试都是与依赖隔离有关。我们不希望给fs依赖引入任何东西,从而影响我们的测试。当然,这是一个极端的例子,但让我们有逻辑地遵循规则。

使用Mockery作为Jasmine测试的一部分,我们可以处理require调用,将fs模块替换为自己模拟的版本。

Mockery是一个非常好的工具。只是要记住,启用它之后,所有的require调用都会被路由到Mockery!

spy

spy在Jasmine中,对代码注入最有效。从本质上说,它们是一个stub和一个mock,两者之间糅合成一个对象。

所以,我们决定,将sum函数从文件中读取JSON和sum函数从参数列表中读取这两种方式像如下代码这样组合在一起:

exports.sum = function (func, data) {
  var data = JSON.parse(func.apply(this, data));
  return data.a + data.b;
};
exports.getByFile = function (file) {
  var fs = require('fs');
  return fs.readFileSync(file, 'utf8');
};
exports.getByParam = function (a, b) {
  return json.stringify({ a: a, b: b });
};

我们现在有了广义数据的输入,并且只在一个地方有sum操作。这不仅能让我们添加新操作(减、乘等),而且还可以将数据从数据操作中分离出来。

对此,我们的Jasmine sepc文件(没有使用Mockery做澄清)如下所示:

var mySum = require('./mySumFunc');
describe('Sum suite Functions', function () {
  it('Adds By Params! ', function () {
    var sum = mySum.sum(mySum.getByParam, [6, 6]);
    expect(sum).toEqual(12);
  });
  it('Adds By File! ', function () {
    var sum = mySum.sum(mySum.getByFile, ['string']);
    expect(sum).toEqual('testableJavaScript');
  });
});

当然,strings文件包含了如下内容:

{ "a": "testable", "b": "JavaScript" }

Jasmine有很多使用技巧,包括可以很容易地禁用测试、模拟setTimer和setInterval,以方便测试、异步测试支持,请访问其主页检查所有的功能。此外,Jasmine不仅仅用于服务器端JavaScript测试!它可以运行在浏览器上用于客户端JavaScript单元测试;然而,在浏览器上运行Jasmine时,提取其测试结果输出不像用YUI Test进行自动化构建一样容易。Jasmine不支持自定义测试报告的导出,而YUI Test,则是开箱即用的支持。

输出

默认情况下,Jasmine将测试结果转储到屏幕上,对开发测试用例来说这很不错,但不适合自动化运行。不过,通过使用–junitreport,可以指示Jasmine将测试结果转存为有广泛支持的JUnit XML输出格式。默认情况下,所有的测试结果都保存在reports目录下,并以测试套件(describe方法的第一个参数)命名。

总结

对JavaScript进行单元测试并不繁琐。有了这些编写和运行单元测试的优秀工具,完成这项工作有很大的灵活性。我们调查了两个工具:YUI Test和Jasmine。对于JavaScript单元测试,两者都提供了全功能的环境,并且在撰写本文时都是活跃的项目,开发人员会定期添加新功能并修复bug。


作者介绍
非职业「传道授业解惑」的开发者叶一一。
《趣学前端》、《CSS畅想》等系列作者。华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。
如果看完文章有所收获,欢迎点赞👍 | 收藏️ | 留言📝

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。