Facebook 推出 JavaScript 单元测试和自动化 Mock 工具 Jest

  • James Chesters
  • 梅雪松

2014 年 6 月 5 日

话题:JavaScriptFacebook语言 & 开发

Facebook 发布了Jest,一个开源的、基于Jasmine框架的 JavaScript 单元测试工具。

Jest 源于 Facebook 两年前的构想,用于快速、可靠地测试 Web 聊天应用。它吸引了公司内部的兴趣,Facebook 的一名软件工程师 Jeff Morrison 半年前又重拾这个项目,改善它的性能,并将其开源。

在最基础层面,Jest 被设计用于快速、简单地编写地道的 JavaScript 测试。Jest 自动模拟 require() 返回的CommonJS模块,并提供了包括内置的测试环境 Dom API 支持、合理的默认值、预处理代码和默认执行并行测试在内的特性。通过在并行进程中同时运行测试,Jest 让测试更快地结束。

Morrison 说:

Jest 的目标是减少开始测试一个项目所要花费的时间和认知负荷,因此它提供了大部分你需要的现成工具:快速的命令行接口、Mock 工具集以及它的自动模块 Mock 系统。

此外,如果你在寻找隔离工具例如 Mock 库,大部分其它工具将让你在测试中(甚至经常在你的主代码中)写一些不尽如人意的样板代码,以使其生效。

我们已经在 Facebook 亲眼看到花更多的时间用于开发你的应用是多么重要(相对于花时间去准备开发你的应用),而这就是 Jest 关注并正在解决的问题。

Jest 与 Jasmine 框架的区别是在后者之上增加了一些层。最值得注意的是,运行测试时,Jest 会自动模拟依赖。Jest 自动为每个依赖的模块生成 Mock,并默认提供这些 Mock,这样就可以很容易地隔离模块的依赖。Morrison 说对于新测试,默认会进行隔离,开发人员现在也能够“完全控制”需要隔离多少模块。每个测试都可以指明哪些模块应该或者不应该 Mock。

关于自动化 Mock,Facebook 的文档有进一步的说明

实际上,Jest 在测试环境中执行自己的 require() 函数。Jest 的自定义 require() 函数加载真正的模块,检查它是什么样子,然后基于它所看到的创建一个 Mock 版本并返回。也就是说,Jest 将给你一个与真实模块具有相同形状的对象,但它模拟每一个 Export 值而不是实际的值。

尽管 Jest 引入了自动化 Mock,需要注意的是,开发者仍然可以使用 jest.mock() 和 jest.dontMock() 控制哪些应该或者不应该进行 Mock。

来自社区的反应绝大部分都很正面。在 Hacker News,用户Cthulu 说

看起来很有趣:我们现在的 AngularJS 项目的测试套件越来越慢,部分原因是逐渐增加的测试,但主要的性能瓶颈是:

  • 没有并行,即使测试套件全部是独立的;
  • DOM 测试,导致大量的 GC 暂停;
  • (可能是)PhantomJS 启动和初始化(未度量)。

我已经做了简单的优化,将我的那些测试分成两半,开两个终端运行(开发时和持续测试中),但它看来有点玄。

直接应对依赖注入和 AngularJS,Facebook 说:“Jest 使用不同的方法来达到相同的结果。”对于 Angular,依赖作为参数进行传递,因此测试很容易写。然而,Facebook 指出,为了 Angular 中函数的可测性,开发者必须遵循其特定模式,将其传递给 Angular 的依赖注入框架。Jest 的解决方案略有不同:

Jest 也能以 Angular 相同的方式 Mock 依赖,但它使用 CommonJS,而不是构建一个特定的模块加载器。这让你能够测试任何使用 CommonJS 的现有代码,不需要重度重构以使其兼容其它模块系统。

用户 Caiob 认同关于 Jest 的乐观情绪,他也是这种依赖注入方法的拥护者,他说:“Facebook 能够提升像 Jasmine 这样的现有 / 熟悉的工具,这非常棒。并且,我喜欢他们处理 CommonJS 模块的方式。”

Morrison 说,通过 Jest,Facebook 希望开始这样一种趋势,让测试变得更简单,让开发者有更多时间开发应用。InfoQ 读者如果想参与这个项目,可以检出Github 库并发送 Pull 请求,或者在 Freenode 加入 #jestjs。

查看英文原文:Facebook Unveils Jest for JavaScript Unit Testing, Automatic Mocking

JavaScriptFacebook语言 & 开发