サブスクリプションとサブジェクトのサブスクライブ解除関数呼び出しをテストする方法を見つけたいのですが。
私はいくつかの可能な解決策を思いつきましたが、これらのすべてには長所と短所があります。テストのために変数のアクセス修飾子を変更したくないことに注意してください。
その場合、サブスクリプションを格納するプライベートクラス変数があります。
component.ts:
private mySubscription: Subscription;
//...
ngOnInit(): void {
this.mySubscription = this.store
.select(mySelector)
.subscribe((value: any) => console.log(value));
}
ngOnDestroy(): void {
this.mySubscription.unsubscribe();
}
component.spec.ts:
spyOn(component['mySubscription'], 'unsubscribe');
component.ngOnDestroy();
expect(component['mySubscription'].unsubscribe).toHaveBeenCalledTimes(1);
長所:
短所:
component.ts:オプション1と同じ
component.spec.ts:
spyOn(Subscription.prototype, 'unsubscribe');
component.ngOnDestroy();
expect(Subscription.prototype.unsubscribe).toHaveBeenCalledTimes(1);
長所:
短所:
subscription.helper.ts:
export class SubscriptionHelper {
static unsubscribeAll(...subscriptions: Subscription[]) {
subscriptions.forEach((subscription: Subscription) => {
subscription.unsubscribe();
});
}
}
component.ts:オプション1と同じですが、ngOnDestroyが異なります:
ngOnDestroy(): void {
SubscriptionHelper.unsubscribeAll(this.mySubscription);
}
component.spec.ts:
spyOn(SubscriptionHelper, 'unsubscribeAll');
component.ngOnDestroy();
expect(SubscriptionHelper.unsubscribeAll).toHaveBeenCalledTimes(1);
長所:
短所:
君たちは何を示唆しているの?単体テストでクリーンアップをどのようにテストしますか?
私はまったく同じ問題を抱えていました、これが私の解決策です:
component.ts:
private subscription: Subscription;
//...
ngOnInit(): void {
this.subscription = this.route.paramMap.subscribe((paramMap: ParamMap) => {
// ...
});
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
component.spec.ts:
let dataMock;
let storeMock: Store;
let storeStub: {
select: Function,
dispatch: Function
};
let paramMapMock: ParamMap;
let paramMapSubscription: Subscription;
let paramMapObservable: Observable<ParamMap>;
let activatedRouteMock: ActivatedRoute;
let activatedRouteStub: {
paramMap: Observable<ParamMap>;
};
beforeEach(async(() => {
dataMock = { /* some test data */ };
storeStub = {
select: (fn: Function) => of((id: string) => dataMock),
dispatch: jasmine.createSpy('dispatch')
};
paramMapMock = {
keys: [],
has: jasmine.createSpy('has'),
get: jasmine.createSpy('get'),
getAll: jasmine.createSpy('getAll')
};
paramMapSubscription = new Subscription();
paramMapObservable = new Observable<ParamMap>();
spyOn(paramMapSubscription, 'unsubscribe').and.callThrough();
spyOn(paramMapObservable, 'subscribe').and.callFake((fn: Function): Subscription => {
fn(paramMapMock);
return paramMapSubscription;
});
activatedRouteStub = {
paramMap: paramMapObservable
};
TestBed.configureTestingModule({
// ...
providers: [
{ provide: Store, useValue: storeStub },
{ provide: ActivatedRoute, useValue: activatedRouteStub }
]
})
.compileComponents();
}));
// ...
it('unsubscribes when destoryed', () => {
fixture.detectChanges();
component.ngOnDestroy();
expect(paramMapSubscription.unsubscribe).toHaveBeenCalled();
});
これは私にとってはうまくいきます、あなたにもそれがうまくいくことを願っています!
よろしいですか?
component.mySubscription = new Subscription();
spyOn(component.mySubscription, 'unsubscribe');
component.ngOnDestroy();
expect(component.mySubscription.unsubscribe).toHaveBeenCalledTimes(1);
私がオープンな推論であったとしても、私はコメントから離れて、より多くのスペースを獲得します。これがSOによって受け入れられることを願っています。
コンポーネントがすべてのサブスクリプションで登録解除を呼び出すことをテストしたい
これはテスト設計の興味深いケースだと思います。
コンポーネントが破棄されたときにサブスクリプションを存続させないことが重要であることは誰もが知っているので、これをテストする方法を検討する価値があります。
同時に、これは実装の詳細と見なすことができ、「公的にアクセス可能なものに属していません。 SWコンポーネントがそのAPIを介して公開するBehavior "また、テストとコードを密に結合したくない場合は、パブリックAPIをテストの重点領域にする必要があります。これは、リファクタリングを妨げるものです。
さらに、AFAIK RxJSは、特定の瞬間にすべてのアクティブなサブスクリプションを一覧表示するメカニズムを提供しないため、これをテストする方法を見つける作業は私たちに残っています。
したがって、すべてのサブスクリプションがサブスクライブされていないことをテストするという目標に到達したい場合は、これを可能にする特定の設計を採用する必要があります。すべてのサブスクリプションを格納する配列を使用し、すべてのサブスクリプションが閉じているかどうかを確認します。これはSubscriptionHelper
の行です。
しかし、これでも必ずしも安全な場所にいるわけではありません。常に新しいサブスクリプションを作成し、それを配列に追加することはできません。これは、コードでこれを行うのを忘れたためかもしれません。
したがって、これをテストできるのは、コーディング規律に固執する場合、つまり、サブスクリプションを配列に追加する場合のみです。ただし、これは、ngOnDestroy
メソッドですべてのサブスクリプションを確実にサブスクライブ解除することと同じです。これもコーディングの規律です。
では、テストの最終目的が重要であっても、そのようなテストを行うことは本当に意味がありますか?コードレビューで達成すべきものではないでしょうか?
非常に好奇心が強い意見を読む
最後のポイントについて
Unsubscribe関数が特定のサブスクリプションで呼び出されたことをテストできません。
あなたはそれを実際に行うことができます。
// get your subscrption
const mySubscription = component['mySubscription'];
// use the reference to confirm that it was called on that specific subscription only.
expect(SubscriptionHelper.unsubscribeAll).toHaveBeenCalledWith(mySubscription);
さて、テストに関しては、パブリックメンバーを確認/アクセス/呼び出しし、その効果をテスト/期待するだけです。
贅沢なJavaScriptを使用して、プライベートメンバーを期待/検証していますが、それでも問題ありません。それでも私は間違っているかもしれません。生産的な批判とコメントを歓迎します。