Overview
Time: 5min
In this module, we will learn to use a fake dependency to isolate our tests
Learning Outcomes
- How to fake out a dependency
- How to fake out a dependency with an inline fake copy of a dependency
- How to Use a Jasmine
spyOn()
to intercept service calls - How to override the dependency injection system to pass in a fake when the real dependency is called
- Hot to use the real service but intercept calls to it with a Jasmine spy
Code for the Completed Lesson
To obtain the code for the completed lesson execute the following git commands.
git clone 'https://firebootcamp:Angular2rocks!@firebootcamp.visualstudio.com/FireBootCamp.Angular/_git/firebootcamp-testing'
git branch -a
git checkout -q 04
Refactor code to have a beforeEach block
Time: 10min
The Jasmine framework has many helpful methods for managing build up and tears down of code for each or all tests in a test suite. The beforeEach()
method is the most commonly used helper to ensure before each test in a describe blocks suite of tests certain code is set up for the test like its dependencies.
- Add a beforeEach block and move the creation of a new joke component into it so each test will have a new JokeComponent for each test.
- Add a global component property to the top of the describe block to be used in the each test or spec
src/app/joke/joke.component.spec.ts
import { JokeComponent } from './joke.component';
describe(`Component: Joke Component`, () => {
let component: JokeComponent;
beforeEach(() => {
component = new JokeComponent(null);
});
it(`should add 1 + 1`, () => {
expect(1 + 1).toEqual(2);
});
it(`should have a title of 'Chuck Norris Jokes`, () => {
expect(component.title).toEqual('Chuck Norris Jokes');
});
});
Add fake jokeService to the beforeEach
Time: 15min
One of the main options you have for faking a dependency like a joke service is to have a fake implementation of the joke service inline in your spec file which implements only the methods you want to test with predictable return values to check. This approach is a very valid and many prefer to isolate their test from changes which might happen in the real implements. However many also prefer to exercise their real service code and only intercept the method calls, which means less refactoring of all the files with inline copies. Both are great approaches, and it is encouraged to try both and learn which work best or use them in combination.
- Add
jokeService
property to top of the describe block - Add the
jokeService
fake to the beforeEach block
src/app/joke/joke.component.spec.ts
describe(`Component: Joke Component`, () => {
let component: JokeComponent;
let jokeService: any;
beforeEach(() => {
jokeService = {
getJoke: () => Observable.of('FAKE JOKE')
};
component = new JokeComponent(jokeService);
});
Add a spyOn()
method to a new test to check the joke contents
Time: 15min
Jasmine has test double functions called spies. A spy can stub any function and tracks calls to it and all arguments. A spy only exists in the describe or a it block in which it is defined and will be removed after each spec. There are special matchers for interacting with spies- Add jokeService
property to the top of the describe block. You can read more in the Jasmine docs here https://jasmine.github.io/2.5/introduction
- Create a new
it
block to test thejoke
property is being set correctly on initialization of the component - Add a
spyOn
function. You can see this spy takes the service to fake and the method as a string as a second parameter of the method on the service to intercept. You can do many things when intercepting a call to the method like return a specific value, call through to the real function or passing a fake of your own function. In this case, we will return anObservable.of('Fake Service')
, so we will need to importof
from rxjs and to keep it easy we will import the whole library in one goimport 'rxjs/Rx';
. - Call
component.ngOnInit()
to trigger the call to the service - Check if the components joke is set to the
"FAKE JOKE"
we return from the spyOn function
src/app/joke/joke.component.spec.ts
it('should set the joke property when component intiialised', () => {
spyOn(jokeService, 'getJoke')
.and.returnValue(Observable.of('FAKE JOKE'));
component.ngOnInit();
expect(component.joke).toEqual('FAKE JOKE');
});
Final Code
Time: 0min
src/app/joke/joke.component.spec.ts
import { JokeComponent } from './joke.component';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
describe(`Component: Joke Component`, () => {
let component: JokeComponent;
let jokeService: any;
beforeEach(() => {
jokeService = {
getJoke: () => Observable.of('FAKE JOKE')
};
component = new JokeComponent(jokeService);
});
it(`should add 1 + 1`, () => {
expect(1 + 1).toEqual(2);
});
it(`should have a title of 'Chuck Norris Jokes`, () => {
expect(component.title).toEqual('Chuck Norris Jokes');
});
it('should set the joke property when component intiialised', () => {
spyOn(jokeService, 'getJoke')
.and.returnValue(Observable.of('FAKE JOKE'));
component.ngOnInit();
expect(component.joke).toEqual('FAKE JOKE');
});
});
Summary
Time: 5min
In this lesson, we looked how to fake a service and how to use a Jasmine spy. In the next lesson, we will look at How to pass in the real service using the TestBed API from Angular and spyOn this. We will also look at interacting with the component's template making a shallow test.