我创建了以下角度工厂名为" juicefactory"它返回以下内容:
return {
aj: pathbuilder.build.bind(this, 'apple', 'juice'),
oj: pathbuilder.build.bind(this, 'orange', 'juice'),
mj: pathbuilder.build.bind(this, 'mango', 'juice')
};
并使用茉莉花编写以下单元测试用例。
before(function(){
mockpathbuilder = {
build: function(fruit, type) {
return fruit & ' ' & type;
}
};
module(function ($provide) {
$provide.value('pathbuilder', mockpathbuilder);
});
});
it('should return value from mock dependency', function () {
spyon(mockpathbuilder, 'build');
juicefactory['aj']();
expect(mockpathbuilder.build).toHaveBeenCalledWith('apple', 'juice');
});
通过代码调试时,它使用两个参数调用模拟的构建方法,但由于某种原因断言失败。能帮助你解决上面代码中缺少的内容吗?
答案 0 :(得分:1)
这可能是一个棘手的问题。
首先,了解bind
返回一个新函数,该函数使用强制上下文包装对原始函数的引用副本。
这就是为什么即使您稍后重新定义原始函数,绑定函数也会以相同的方式工作:
var pathbuilder = {
build: function() {
console.log('Original');
}
};
var juicefactory = {
a: pathbuilder.build.bind(this)
};
pathbuilder.build(); // Logs: Original
juicefactory.a(); // Logs: Original
pathbuilder.build = function() {
console.log('New');
};
pathbuilder.build(); // Logs: New
juicefactory.a(); // Still logs: Original
您的案例中的问题是spyOn
会将新函数分配给pathbuiler.build
,这是一个新的包装函数,其中包含对原始函数的引用。
这意味着对pathbuilder.build
的所有后续调用都将触及由spyOn
创建的新包装函数,调用将被注册,然后将调用原始函数(如果and.callThrough()
是在创建间谍时使用。)
但是,使用juicefactory.a
创建的对bind
的调用将触及原始pathbuilder.build
函数,而不是spyOn
创建的包装器。这意味着不会记录通话。
一种解决方案是将spyOn(mockpathbuilder, 'build')
移出it
块,然后移动到创建模块的before
。
这基本上意味着当在测试环境中创建juicefactory
并执行pathbuilder.build.bind
时,pathbuilder.build
将成为spyOn
创建的包装函数,一切都会工作
另一个解决方案是将pathbuilder.build.bind
的执行包装在一个函数中:
aj: function() {
pathbuilder.build.bind(this, 'apple', 'juice')();
}
这意味着每次执行aj
函数时都会在运行时完成绑定。但是,除非这是您真正想要的功能,否则我不建议这样做。它的性能也更差(尽管很可能是微不足道的),因为绑定可能会发生多次。