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

453 查看

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。