Jasmineで(メソッドではなく)値プロパティをスパイする方法


115

ジャスミンspyOnはメソッドの動作を変更するのに適していますが、オブジェクトの(プロパティではなく)値プロパティを変更する方法はありますか?コードは次のようになります:

spyOn(myObj, 'valueA').andReturn(1);
expect(myObj.valueA).toBe(1);

回答:


97

2017年2月、この機能を追加するPRを統合し、2017年4月にリリースしました。

したがって、使用するゲッター/セッターをスパイするに const spy = spyOnProperty(myObj, 'myGetterName', 'get'); は、myObjがインスタンスで、 'myGetterName'はクラスで定義されているインスタンスの名前でget myGetterName() {}、3番目のパラメーターは型getまたはsetです。

で作成したスパイですでに使用しているのと同じアサーションを使用できますspyOn

たとえば、次のことができます。

const spy = spyOnProperty(myObj, 'myGetterName', 'get'); // to stub and return nothing. Just spy and stub.
const spy = spyOnProperty(myObj, 'myGetterName', 'get').and.returnValue(1); // to stub and return 1 or any value as needed.
const spy = spyOnProperty(myObj, 'myGetterName', 'get').and.callThrough(); // Call the real thing.

興味がある場合にこのメソッドを使用できるgithubソースコードの行を次に示します。

https://github.com/jasmine/jasmine/blob/7f8f2b5e7a7af70d7f6b629331eb6fe0a7cb9279/src/core/requireInterface.js#L199

元の質問にジャスミン2.6.1で答えると、次のようになります。

const spy = spyOnProperty(myObj, 'valueA', 'get').andReturn(1);
expect(myObj.valueA).toBe(1);
expect(spy).toHaveBeenCalled();

7
どうすればこれを行うかvalueAですObservableSubject?取得中Property valueA does not have access type get
Ka Mok

4
それはおそらく、そのプロパティでは使用できないことを意味します。spyOnPropertyはgetOwnPropertyDescriptorを使用して、そのプロパティ記述子のアクセスタイプget | setが存在するかどうかを確認しています。取得しようとしているエラーは、プロパティ記述子が設定されていないか、スパイしようとしているプロパティに対して取得されているためです。Jasmineはこれを行います:const descriptor = Object.getOwnPropertyDescriptor ... if(!descriptor [accessType]){//エラーがスローされます}
Juan

それで、明示的なゲッターおよびセッターメソッドなしでプロパティをスパイする方法はありませんか?スパイするために使用されるプロパティです。
ドミニク

:@Dominikは、ここで私は、すべての長い記事ではこれに関連したフードのものの下に書いたmedium.com/@juanlizarazo/...
フアン

1
@Mathieuスパイに指示したことからすでにわかっていることを主張するだけなので、これは良い主張ではありませんが、彼らが求めていたこととまったく同じ質問コードスニペットです¯_(ツ)_ /¯ポイント彼らの質問の1つは、プロパティをスパイする方法であり、具体的な例ではありませんでした。
フアン

12

オブジェクトで直接変更できない理由は何ですか?JavaScriptがオブジェクトのプロパティの可視性を強制するかのようではありません。


1
spyOn明示的に使用すると、モックが必要であることを明示的に示しますが、プロパティを直接設定すると、暗黙的にモックが必要であることを示します。他のケースでは、オブジェクトの内部動作を変更したくない場合があります。たとえば、配列のlengthプロパティを変更すると、配列がトリミングされるため、モックの方が優れています
Shuping

@Shuping、この場合、あなたはあざけることはないでしょう。あなたは完全に大丈夫ですスタブするでしょう。あなたは、あなたがで達成しようとしていたものであるテストの内側でのみ「振る舞いを変える」でしょうspyOn
Fabio Milheiro 2014

おそらく、ランタイムオブジェクトのプロトタイプをスパイして、プロパティが実行時に存在することを確認する必要があります。spyOnプロパティが存在しない場合、Jasmine はテストに失敗します。
sennett 2015

2
一つの例は、セットまたは削除window.sessionStorageのにある:TypeError: Cannot assign to read only property 'sessionStorage' of object '#<Window>'
クリスSattinger

2
JavaScriptでオブジェクトプロパティを再割り当てできるとは限りません
Renaud

12

Jasmineにはその機能はありませんが、を使用して何かを一緒にハッキングできる可能性がありますObject.defineProperty

コードをリファクタリングしてゲッター関数を使用し、ゲッターをスパイすることができます。

spyOn(myObj, 'getValueA').andReturn(1);
expect(myObj.getValueA()).toBe(1);

はい、それが今私ができることです。
2014年

4
ジャスミン2の場合:and.returnValue(1)
jtzero

9

最良の方法はを使用することspyOnPropertyです。3つのパラメーターを想定しているため、3番目のパラメーターとして渡すgetset、3番目のパラメーターとして渡す必要があります。

const div = fixture.debugElement.query(By.css('.ellipsis-overflow'));
// now mock properties
spyOnProperty(div.nativeElement, 'clientWidth', 'get').and.returnValue(1400);
spyOnProperty(div.nativeElement, 'scrollWidth', 'get').and.returnValue(2400);

ここgetclientWidthdiv.nativeElementオブジェクトのを設定しています。


6

ES6(Babel)またはTypeScriptを使用している場合は、getおよびsetアクセサーを使用してプロパティをスタブできます。

export class SomeClassStub {
  getValueA = jasmine.createSpy('getValueA');
  setValueA = jasmine.createSpy('setValueA');
  get valueA() { return this.getValueA(); }
  set valueA(value) { this.setValueA(value); }
}

次に、テストでプロパティが設定されていることを確認できます:

stub.valueA = 'foo';

expect(stub.setValueA).toHaveBeenCalledWith('foo');

または、ゲッターがテスト中のクラスの一部である場合、スタブをサブクラスに挿入できます。
ccprog

6

これを行う正しい方法は、spy onプロパティを使用することです。これにより、特定の値を持つオブジェクトのプロパティをシミュレートできます。

const spy = spyOnProperty(myObj, 'valueA').and.returnValue(1);
expect(myObj.valueA).toBe(1);
expect(spy).toHaveBeenCalled();

1

テストが必要なこのようなメソッドがあると仮定しますsrc小さな画像のプロパティはチェックが必要です

function reportABCEvent(cat, type, val) {
                var i1 = new Image(1, 1);
                var link = getABC('creosote');
                    link += "&category=" + String(cat);
                    link += "&event_type=" + String(type);
                    link += "&event_value=" + String(val);
                    i1.src = link;
                }

以下のspyOn()は、「新しい画像」にテストからの偽のコードを供給させます。spyOnコードは、srcプロパティのみを持つオブジェクトを返します

変数 "hook"は、SpyOnの偽のコードに表示されるようにスコープが設定されているため、後で "reportABCEvent"が呼び出された後も

describe("Alphabetic.ads", function() {
    it("ABC events create an image request", function() {
    var hook={};
    spyOn(window, 'Image').andCallFake( function(x,y) {
          hook={ src: {} }
          return hook;
      }
      );
      reportABCEvent('testa', 'testb', 'testc');
      expect(hook.src).
      toEqual('[zubzub]&arg1=testa&arg2=testb&event_value=testc');
    });

これはジャスミン1.3用ですが、「andCallFake」が2.0の名前に変更されている場合は2.0で動作する可能性があります


1

私は剣道グリッドを使用しているため、実装をゲッターメソッドに変更することはできませんが、これをテストして(グリッドのモックを作成)、グリッド自体はテストしません。私はスパイオブジェクトを使用していましたが、これはプロパティのモッキングをサポートしていないため、これを行います:

    this.$scope.ticketsGrid = { 
        showColumn: jasmine.createSpy('showColumn'),
        hideColumn: jasmine.createSpy('hideColumn'),
        select: jasmine.createSpy('select'),
        dataItem: jasmine.createSpy('dataItem'),
        _data: []
    } 

少し曲がりくねっていますが、それは御馳走を働かせます


0

ここのパーティーには少し遅れますが、

あなたは直接callsオブジェクトにアクセスすることができました、そしてそれはあなたに各呼び出しのための変数を与えることができます

expect(spy.calls.argsFor(0)[0].value).toBe(expectedValue)

-3

変数をモックすることはできませんが、そのためのゲッター関数を作成し、スペックファイルにそのメソッドをモックすることができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.