プロパティを持つjasmine.createSpyObj

Oct 28 2020

Angularテストで依存関係をモックするとき、私は通常、以下を使用してスパイオブジェクトを作成しますjasmine.createSpyObj

const serviceSpy= jasmine.createSpyObj('MyService', ['method']);

次に、それをTestBedに提供します。

  providers: [
    {provide: MyService, useValue: serviceSpy}
  ]

テストで使用する場合、目的の戻り値を指定できます。

serviceSpy.method.and.returnValue(of([...]));

今、私もプロパティをモックする必要があり、それがどのように行われるべきかを見つけることができません。createSpyObjプロパティ名の定義を許可します:

const serviceSpy= jasmine.createSpyObj('MyService', ['method'], ['property']);

しかし、私はそこにある多数の記事と回答に基づいてさまざまな解決策を試しましたが、成功しませんでした。例:

// Cannot read property 'and' of undefined    
serviceSpy.property.and.returnValue(true);  
// not declared configurable
spyOnProperty(serviceSpy, 'property').and.returnValue(true);  
// no build errors, but value stays 'undefined'
serviceSpy.property = true;  

私がそれを「半分」動作させることができる唯一の方法は:

let fakeValue = true;
const serviceSpy= jasmine.createSpyObj('MyService', ['method'], {'property': fakeValue});

ここでの問題は、それが作成時に1回限りのセットであるということです。テストで期待値を変更したいのですが、うまくいきません。

fakeValue = false;
serviceSpy.property ==> stays to the initial value 'true';

スパイオブジェクトを作成することで、モックメソッドとプロパティの両方に対する解決策はspyOnありspyOnPropertyますか?それとも、使用できる独自の偽のクラスを作成する必要がありますか?

また、createSpyObj定義内のプロパティ配列の使用法を知りたいです。これまでのところ、それを説明する例をWeb上で見たことがありません。

回答

5 jonrsharpe Oct 28 2020 at 01:29

あたりのドキュメント(強調鉱山):

プロパティの配列またはハッシュを3番目の引数としてに渡すことにより、いくつかのプロパティを持つスパイオブジェクトをすばやく作成できますcreateSpyObj。この場合、作成されたスパイへの参照がないため、後でスパイ戦略を変更する必要がある場合は、Object.getOwnPropertyDescriptorアプローチを使用する必要があります

it("creates a spy object with properties", function() {
  let obj = createSpyObj("myObject", {}, { x: 3, y: 4 });
  expect(obj.x).toEqual(3);

  Object.getOwnPropertyDescriptor(obj, "x").get.and.returnValue(7);
  expect(obj.x).toEqual(7);
});

スパイされたプロパティは記述子であるため(Object.definePropertyMDNなどを参照)、スパイオブジェクトにアクセスするには、記述子オブジェクトを取得して、それに定義されているメソッドgetsetメソッドを操作する必要があります。


TypeScriptでは、コンパイラは少し助けが必要です。createSpyObj戻りのいずれかany、またはSpyObj<T>、とSpyObjのみ定義方法を上に見張られているとおり

type SpyObj<T> = T & {
    [K in keyof T]: T[K] extends Func ? T[K] & Spy<T[K]> : T[K];
               // |     if it's a     |    spy on it     | otherwise leave
               // |     callable      |                  | it alone
};

したがって.and、記述子のゲッターにアクセスするには、オプションのチェーン(Object.getOwnPropertyDescriptor戻る場合がありますundefined)と:への型アサーションが必要ですSpy。

(Object.getOwnPropertyDescriptor(obj, "x")?.get as Spy<() => number>).and.returnValue(7);

遊び場

1 IanGrainger Nov 11 2020 at 17:57

どうもありがとう@jonrsharpe!関数を追加したので、次のことができます。

spyPropertyGetter(spy, 'propName').and.returnValue(...)

これは次のように定義されます:

function spyPropertyGetter(
  spyObj: jasmine.SpyObj<any>,
  propName: string
) {
  return Object.getOwnPropertyDescriptor(spyObj, propName).get as jasmine.Spy<
    jasmine.Func
  >;
}