我当前在使用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类的方法的husband.buyFood().
我应该如何处理这个问题,而不必通过buyFood()方法调用断言值更改?
你必须了解Typescript和间谍背后的机制.
我忽略了额外的parens class Parent()
.
打字稿使用幕后的原型继承.因此,原型会将引用的属性从"基类"复制到新类.这就是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操场翻译打字稿.
您的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; }
在实际的间谍方法要复杂得多,但.
你的路线
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(); }