我是单元测试的新手,所以我可能遗漏了一些东西,但我应该如何构建 requirejs 模块以使它们完全可测试?考虑优雅的显示模块模式。
define([], function () {
"use strict";
var func1 = function(){
var data = func2();
};
var func2 = function(){
return db.call();
};
return {
func1 : func1
}
});
据我所知,这是构建 requirejs 模块的最常见模式。如果我错了请纠正我!因此,在这个简单的场景中,我可以轻松地测试 func1
的返回值和行为,因为它是全局的。但是,为了测试 func2
我还必须返回它的引用。对吧?
return {
func1 : func1,
_test_func2 : func2
}
这使得代码稍微不那么漂亮,但总体来说还是可以的。但是,如果我想模拟 func2
并使用 Jasmine spy
替换它的返回值,我将无法做到,因为该方法在闭包中。
所以我的问题是如何构造 requirejs 模块以使其完全可测试?对于这种情况,是否有比揭示模块模式更好的模式?
最佳答案
您确定要测试私有(private)函数 func2 吗?
我认为开发人员在尝试为私有(private)函数编写测试时忽略了单元测试的要点。
在开发软件时,依赖关系让我们掌握了球。而且依赖越多,挤压得越紧。因此,如果您有大量依赖于模块内部工作的测试,那么当您想要更改内部实现时,将会非常痛苦。因此,让您的测试依赖于公共(public)接口(interface),并保持私有(private)内容的私有(private)性。
我的建议:
- 为您的模块设计公共(public)接口(interface)。
- 针对公共(public)接口(interface)编写测试以指定一些预期行为。
- 实现通过该测试所需的代码。
- 重构(如有必要)
- 从第 2 步开始重复,直到所有功能都已通过测试定义,并且所有测试都通过。
在实现和重构阶段,模块的内部会发生变化。例如,func2 可以拆分为不同的函数。危险在于,如果您有专门针对 func2 的测试,那么您在重构时可能不得不重写测试。
单元测试的主要好处之一是它们确保我们在更改模块的内部工作方式时不会破坏现有功能。如果重构意味着您需要更新测试,您就会开始失去这种好处。
如果 func2 中的代码变得如此复杂以至于您想对其进行显式测试,则将其提取到一个单独的模块中,您可以在其中通过针对公共(public)接口(interface)的单元测试来定义行为。以具有易于理解的公共(public)接口(interface)的小型、经过良好测试的模块为目标。
如果您正在寻求有关单元测试的帮助,我强烈推荐 Kent Beck 的书“TDD by example”。编写糟糕的单元测试将成为障碍而不是好处,在我看来,TDD 是唯一的出路。
关于javascript - 如何编写可测试的 requirejs 模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19588622/