I am trying to test a function that unsubscribes from all subscriptions:
ngOnDestroy() {
this.tryUnsubscribe(this.carsSubscription);
this.tryUnsubscribe(this.partsSubscription);
this.tryUnsubscribe(this.shopsSubscription);
}
This is the test I wrote for the function:
it('should unsubscribe from subscriptions ', () => {
spyOn(component, "tryUnsubscribe");
component.ngOnDestroy();
expect(component.tryUnsubscribe).toHaveBeenCalledWith(component['carsSubscription']);
expect(component.tryUnsubscribe).toHaveBeenCalledWith(component['partsSubscription']);
expect(component.tryUnsubscribe).toHaveBeenCalledWith(component['shopsSubscription']);
});
The problem:
If I comment out a function call, the tests still passes.
ngOnDestroy() {
this.tryUnsubscribe(this.carsSubscription);
//this.tryUnsubscribe(this.partsSubscription);
this.tryUnsubscribe(this.shopsSubscription);
}
Only if I comment out all of these function calls, the test fails:
ngOnDestroy() {
//this.tryUnsubscribe(this.carsSubscription);
//this.tryUnsubscribe(this.partsSubscription);
//this.tryUnsubscribe(this.shopsSubscription);
}
How to properly test this kind of function? What am I doing wrong?
Create a Mock API with Jasminejson file in your root directory. If not, you can set it up with this command: npm init -y . Your test should pass! Try changing the value of a to false, and running it again to see what it looks like when a test fails.
Jasmine provides the spyOn() function for such purposes. spyOn() takes two parameters: the first parameter is the name of the object and the second parameter is the name of the method to be spied upon. It replaces the spied method with a stub, and does not actually execute the real method.
callFake(fn)Tell the spy to call a fake implementation when invoked.
TestBed is a mock environment to run Angular2 component tests without the browser.
It is also possible to check all arguments at once using Jasmine calls.allArgs() method:
expect(spy.calls.allArgs()).toEqual([
[component.carsSubscription],
[component.partsSubscription],
[component.shopsSubscription]
]);
Here is modified Fabian Küng's answer in stackblitz.
I would rewrite your test to the following:
it('should unsubscribe from subscriptions ', () => {
const spy = spyOn(component, 'tryUnsubscribe');
component.ngOnDestroy();
// Check how many times the spy was called
expect(spy).toHaveBeenCalledTimes(3);
});
If you now uncomment one of the tryUnsubscribe
calls, the test should fail as the spy was only called twice.
Another approach would be to mock the subscriptions or just set them to a dummy value to test that inside the ngDestroy
tryUnsubscribe
was called with those 3 component variables:
it('test unsubscribing', () => {
// Mock values
component.carsSubscription = Observable.of(1).subscribe(() => {});
component.partsSubscription = Observable.of(1).subscribe(() => {});
component.shopsSubscription = Observable.of(1).subscribe(() => {});
const spy = spyOn(component, 'tryUnsubscribe').and.callThrough();
component.ngOnDestroy();
// Check how many times the spy was called
expect(spy).toHaveBeenCalledTimes(3);
// Check arguments
expect(spy.calls.all()[0].args[0]).toEqual(component.carsSubscription);
expect(spy.calls.all()[1].args[0]).toEqual(component.partsSubscription);
expect(spy.calls.all()[2].args[0]).toEqual(component.shopsSubscription);
});
Here is a working stackblitz with the test.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With