Javascript jasmine监视继承的方法(使用typescript)在toHaveBeenCalled()中无法正常工作

Javascript jasmine监视继承的方法(使用typescript)在toHaveBeenCalled()中无法正常工作,javascript,inheritance,typescript,jasmine,Javascript,Inheritance,Typescript,Jasmine,我目前在监视typescript类中调用的继承方法时遇到了一个问题,其中ToHaveBeenCall()方法返回false,即使被监视的方法被调用。看看下面的场景 我有两门课,是用打字机写的 class Parent() { buyFood() { // buy food } } class Husband extends Parent { makeDinner() { super.buyFood(); // make d

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

我有两门课,是用打字机写的

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


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

您必须了解Typescript和监视背后的机制

首先是打字脚本。。。 我忽略了
类Parent()
中的额外参数

Typescript在幕后使用原型继承。因此,原型将引用的属性从“基类”复制到新类。这是
for
循环在
\uu 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));
你可以用这个来翻译打字脚本

您的
super
表达式调用父类的
buyFood()
方法,而不是“继承的”
丈夫的方法

看到线了吗

_super.prototype.buyFood.call(this);
并遵循
\u super
参考

现在茉莉花间谍。。。 间谍将用充当代理的间谍函数替换传递对象的命名函数。该代理现在可以跟踪调用,并根据编程行为控制是调用原始函数、伪函数、返回值还是不执行任何操作(默认)

非常简化的
spyOn()
可以如下所示:

function spyOn(obj, fn) {
    var origFn = obj[fn],
        spy = function() {
            spy.calls.push(arguments);
        };

    spy.calls = [];

    obj[fn] = spy;
}
但问题要复杂得多

你的线路

spyOn(husband, 'buyFood');
将实际用间谍替换
丈夫
实例中的方法。但是,由于代码调用基类(父原型)的引用,因此它与您刚才替换的函数不同

解决方案 您应该调用
this
引用的方法

class Husband extends Parent {
    makeDinner() {
        // call byFood() via this
        this.buyFood();
    }
}
。。。或者监视父原型(
super
):


使用ES6时,
父.prototype
将无法工作。改用
Object.getPrototypeOf

这就是我的工作原理:

it('Should make a good dinner', () => {
    spyOn(Object.getPrototypeOf(Object.getPrototypeOf(husband), 'buyFood');
    husband.makeDinner();

    expect(Parent.prototype.buyFood).toHaveBeenCalled();
}

测试框架是否支持这一点?JavaScript中的继承充其量是变化无常的。似乎没有任何对继承方法的引用。。。从文档中可以看出,“间谍可以存根任何函数并跟踪对它的调用和所有参数。”那么,也许它不是在原型链上行走。超级!!非常感谢您的详细解释和解决方案!真的非常感谢这非常有帮助!在我的例子中,我在一个子类中有一个方法,它隐藏了一个名为method的超类,因此
spyOn(Parent.prototype,'methodName')太完美了!这个解决方案非常有效!最重要的是,感谢您简洁地解释了它的工作原理:)哇。我喜欢这个解决方案@最后试一试,如果buyFood()是“受保护的”,那该怎么办?对我来说很有效,但奇怪的是
Object.getPrototypeOf()
必须被调用twicei我想这是因为第一次调用会得到类的原型,第二次调用会得到原型的prototypeP.s。这个解决方案是有效的,除了您的示例在“丈夫”后面缺少一个后括号之外。最好添加一个句子来解释什么是错误的,以及建议的代码正在修复什么
it('Should make a good dinner', () => {
    spyOn(Object.getPrototypeOf(Object.getPrototypeOf(husband), 'buyFood');
    husband.makeDinner();

    expect(Parent.prototype.buyFood).toHaveBeenCalled();
}
const spy = spyOn(husband, 'buyFood');
husband.makeDinner();
expect(spy).toHaveBeenCalled();