我当前在使用typescript类中的调用的继承方法时遇到问题,其中toHaveBeenCalled()方法返回false,即使调用了被监视的方法。请看以下场景...
我有两个用TypeScript编写的类
class Parent() {
buyFood() {
// buy food
}
}
class Husband extends Parent {
makeDinner() {
super.buyFood();
// make dinner;
}
}
在我对班级丈夫的测试中,我只关心测试制作晚餐的逻辑,因为超级购买食品的逻辑在其自己的测试套件中进行测试。
因此,我的测试看起来像是以下类型。
let husband:Husband = new Husband();
it('Should make a good dinner', () => {
spyOn(husband, 'buyFood');
husband.makeDinner();
expect(husband.buyFood).toHaveBeenCalled();
}
即使正在调用buyFood(),断言也会失败并显示一条错误,指出从未调用过继承自Parent类的方法的丈夫.buyFood()。
我如何解决这个问题,而不必通过buyFood()方法调用断言值更改?
答案 0 :(得分:38)
你必须了解Typescript和间谍背后的机制。
我忽略了class Parent()
中的额外情况。
Typescript使用幕后的原型继承。因此,原型将从"基类"复制引用的属性。到新班级。这就是for
函数在__extends()
函数中的作用。
这是您将Typescript翻译成的ES5代码:
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var Parent = (function () {
function Parent() {
}
Parent.prototype.buyFood = function () {
// buy food
};
return Parent;
}());
var Husband = (function (_super) {
__extends(Husband, _super);
function Husband() {
return _super.apply(this, arguments) || this;
}
Husband.prototype.makeDinner = function () {
_super.prototype.buyFood.call(this);
// make dinner;
};
return Husband;
}(Parent));
您可以使用此Typescript playground翻译打字稿。
您的super
表达式调用父类的buyFood()
方法,而不是"继承的方法" Husband
。
见行
_super.prototype.buyFood.call(this);
并按照_super
参考。
间谍将通过充当代理的间谍函数替换传递对象的命名函数。该代理现在可以跟踪调用,并根据编程的行为控制是否调用原始函数,伪造,返回值或不执行任何操作(默认)。
非常简化版spyOn()
可能如下所示:
function spyOn(obj, fn) {
var origFn = obj[fn],
spy = function() {
spy.calls.push(arguments);
};
spy.calls = [];
obj[fn] = spy;
}
actual spy method虽然复杂得多。
你的行
spyOn(husband, 'buyFood');
实际上会被间谍替换Husband
的实例中的方法。但是,由于代码调用基类(父原型)的引用,它与您刚刚替换的功能不同。
您应该调用this
引用的方法
class Husband extends Parent {
makeDinner() {
// call byFood() via this
this.buyFood();
}
}
...或监视父原型(super
):
it('Should make a good dinner', () => {
spyOn(Parent.prototype, 'buyFood');
husband.makeDinner();
expect(Parent.prototype.buyFood).toHaveBeenCalled();
}
答案 1 :(得分:0)
使用 ES6 时,Parent.prototype
不起作用。请改用Object.getPrototypeOf
。
这对我有用:
it('Should make a good dinner', () => {
spyOn(Object.getPrototypeOf(Object.getPrototypeOf(husband), 'buyFood');
husband.makeDinner();
expect(Parent.prototype.buyFood).toHaveBeenCalled();
}
答案 2 :(得分:0)
const spy = spyOn(husband, 'buyFood');
husband.makeDinner();
expect(spy).toHaveBeenCalled();