I've been writing some unit tests. A common scenario thing that sends me to the blog.
I had a method that called another method. That's a pretty common scenario. I wanted to spy on the method call to test the first method. However, I then discovered I was not able to call the second method in later tests, because the spy intercepted the call.
This will go better with a sample, so imagine this code:
2
3 method1 () {
4 this.method2();
5 }
6
7 method2(input: string = 'abc') {
8 return input;
9 }
10
11}
method1() makes a call to method2(). For whatever reason, when testing method1() I decided I did not want it to call method2(), so I can write a test like this:
2 spyOn(app, 'method2');
3})
4
5it('should test that method1 calls method2', () => {
6 app.method1();
7 expect(app.method2).toHaveBeenCalled();
8})
This works perfectly. However, then I had another test for method2:
2 expect(app.method2()).toBe('abc'); // this fails, because method is not called
3})
This test always fails, because the spy intercepts the method call, and does not call the method2() function on the class instance. I could use `callThrough()`on the initial spy, however in the code I was working on, method2() had side affects I wanted to avoid when testing method1(). I needed another way.
That second approach is to use the allowRespy() method on Jasmine's Env class instance.
We can rework the beforeEach() to call this:
2 jasmine.getEnv().allowRespy(true);
3 spyOn(app, 'method2');
4})
Then test method1():
2 app.method1();
3 expect(app.method2).toHaveBeenCalled();
4})
This test works, identical to our first test. Testing method2() now can be done if we reset the spy:
2 spyOn(app, 'method2').and.callThrough();
3 expect(app.method2()).toBe('abc'); // this fails, because method is not called
4})
Tada! This updated test works.
Play around with my code sample here. I used Angular because that was a super easy way to get a project w/ Jasmine and Karma all set to go.