TypeScriptクラスの呼び出しの継承されたメソッドをスパイするときに、スパイされているメソッドが呼び出されてもtoHaveBeenCalled()メソッドがfalseを返すという問題が発生しています。次のシナリオを見てください...
TypeScriptで書かれた2つのクラスがあります
class Parent() {
buyFood() {
// buy food
}
}
class Husband extends Parent {
makeDinner() {
super.buyFood();
// make dinner;
}
}
スーパークラスのバイフードのロジックは独自のテストスイートでテストされるため、Husbandクラスのテストでは、夕食を作るためのロジックをテストすることだけに関心があります。
したがって、私のテストは次のようなもののように見えます。
let husband:Husband = new Husband();
it('Should make a good dinner', () => {
spyOn(husband, 'buyFood');
husband.makeDinner();
expect(husband.buyFood).toHaveBeenCalled();
}
BuyFood()が呼び出されているにもかかわらず、アサーションが失敗し、Parentクラスから継承されたメソッドである夫.buyFood()が呼び出されたことがないというエラーが発生します。
この問題は、buyFood()メソッド呼び出しによって値の変更を主張する必要なしにどうすればよいですか?
TypeScriptとスパイの背後にあるメカニズムを理解する必要があります。
class Parent()
の余分な括弧は無視しています。
TypeScriptは、カーテンの後ろでプロトタイプの継承を使用します。したがって、プロトタイプは「基本クラス」から新しいクラスに参照されるプロパティをコピーします。これは、__extends()
関数のfor
ループが行うことです。
これは、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 を使用してTypeScriptを翻訳できます。
super
式は、「継承された」Husband
のメソッドではなく、親クラスのbuyFood()
メソッドを呼び出します。
ラインを見る
__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;
}
_
実際のスパイメソッド は、はるかに複雑です。
あなたのライン
_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();
}
_
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();
}