我有两个模块,ModuleA和ModuleB。 ModuleB依赖于ModuleA。但据我所知,requirejs是一种服务定位器。那么我如何在我的代码中对这种模式进行单元测试。
define('moduleA', function() {
var ModuleA = function() {
this.doSomething = function() {
return true;
}
}
return ModuleA;
});
define('moduleB', ['moduleA'], function(ModuleA) {
var moduleA = new ModuleA();
var ModuleB = function() {
this.doSomethingElse = function() {
if(moduleA.doSomething()) {
// do something else and return
} else {
// do other things and return
}
}
}
return ModuleB
});
/*Test for moduleB*/
define('test', ['moduleB', function(ModuleB) {
describe('', function() {
var moduleB = new ModuleB();
expect(moduleB.doSomethingElse()).toBe(true);
});
});
因为ModuleA会一直初始化。无论如何我可以向ModuleB注入一些模拟并测试吗?我不想使用单身,因为我不确定测试是否会因为无法预料的行为而继续失败。
注意:我只是键入代码,因此它们可能是一些编译错误。
答案 0 :(得分:2)
此代码模式不可单元测试。我想有人可能想出一种方法来欺骗RequireJS加载不同的模块定义并在测试结束时卸载它,但这样太复杂且容易出错,并且不能解决编码错误的问题
模式是不可测试的,因为在moduleB定义中你正在创建moduleA的新实例(加上ModuleA的加载是"硬编码")。为了使其可测试,您需要注入它。考虑类似的事情:
define('moduleB', function() {
var ModuleB = function(moduleA) {
this.__moduleA = moduleA;
this.doSomethingElse = function() {
if(this.__moduleA.doSomething()) {
// do something else and return
} else {
// do other things and return
}
}
}
return ModuleB
});
为了进一步探索这种小型重构,我建议阅读"依赖注入"。跳过像Guice这样的DI工具,只需了解DI想法的核心。
Misko Hevery有几个关于这种OOP模式的有趣帖子,包括如何处理" new"关键字:http://misko.hevery.com/2008/09/10/where-have-all-the-new-operators-gone/
我现在找不到它,但我相信Misko在OOP,继承层次结构(最明显),创建层次结构(谁创建了什么)和依赖层次结构(谁使用谁)方面有好的帖子。这3个层次结构完全不同。通常,如果B类创建A类,它就不应该使用它。 B类的角色似乎是工厂 - 它创造了实例。应该有一些其他类C使用注入的A类实例来执行一些业务逻辑。
作为旁注,因为您已经在使用AMD模块和JS"类"为什么不让你的类/对象外观和行为更像正确的OOP类/对象? Dejavu可以帮助你:http://wojciechszela.com/blog/2014/01/13/object-oriented-programming-in-javascript/