我目前在监视typescript类中调用的继承方法时遇到了一个问题,其中ToHaveBeenCall()方法返回false,即使被监视的方法被调用.看看下面的场景...

我有两门课,都是用 typewriter 写的

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(),但断言仍然失败,错误是丈夫.从未调用从父类继承的方法buyFood().

我应该如何处理这个问题,而不必通过buyFood()方法调用断言值的变化?

推荐答案

你必须理解打字脚本和间谍活动背后的机制.

首先是打字脚本...

我忽略了class Parent()个额外的帕伦.

Typescript在幕后使用原型继承.因此,原型将引用的属性从"基类"复制到新类.这就是for循环在__extends()函数中所做的.

这是您的打字脚本翻译成的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参考.

现在茉莉花间谍...

间谍将用充当代理的间谍函数替换传递对象的命名函数.该代理现在可以跟踪调用,并根据编程行为控制是调用原始函数、伪函数、返回值还是什么都不做(默认).

very简化版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年第instance期中的方法.但是,由于代码调用基类(父原型)的引用,所以它与您刚才替换的函数不同.

解决方案

您应该调用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();
}

Typescript相关问答推荐

在TypScript中的同一数组中验证不同类型

具有映射返回类型的通用设置实用程序

类型脚本如何将嵌套的通用类型展开为父通用类型

无法将select选项的值设置为ngFor循环中的第一个元素

如何根据另一个属性的布尔值来缩小函数属性的返回类型?

数组文字中对象的从键开始枚举

类型脚本类型字段组合

根据另一个属性的值来推断属性的类型

类型{}上不存在属性&STORE&A;-MobX&A;REACT&A;TYPE脚本

对于合并对象中的可选属性(例如选项),类型推断可能是错误的

角效用函数的类型推断

以Angular 自定义快捷菜单

在HighChats列时间序列图中,十字准线未按预期工作

MatTool提示在角垫工作台中不起作用

将带点的对象键重新映射为具有保留值类型的嵌套对象

类型脚本可以推断哪个类型作为参数传递到联合类型中吗?

如何获取受类型脚本泛型约束的有效输入参数

17个Angular 的延迟观察.如何在模板中转义@符号?

如何避免多个类型参数重复?

Typescript不允许在数组中使用联合类型