Angular Unit Testing
Chandan Naresh
Sr Technical Consultant
Introduction
● Angular Testing
● Unit Testing
● (Jasmine, Mocha, Karma)
● End to End Testing
● (
● Integration Testing
Introduction
Pragmatic Unit testing
● Decisions to make
● Testing Recipes
Decisions
Should I write unit tests?
○ Yes
○ Yes!!
Framework to use
○ Jasmine
○ Mocha
Test Runner
○ Karma
Decisions - Angular specific
● Testing Module Setup
○ How much to mock?
○ Isolation vs Being close to production
● Test Method Setup
○ () => { }
○ async() => { }
○ fakeAsync() => { }
Decisions - Angular specific (contd.)
● Locating elements
○ Using DOM API
○ Using DebugElement
● Dispatching events
○ Using DOM API
○ Using DebugElement
Recipes
Simple Component with templateUrl
Recipes - Simple Component with templateUrl
[[Link]]
@Component({
moduleId: [Link],
selector: 'my-app',
templateUrl: '[Link]'
})
export class AppComponent {}
[[Link]]
<h1>My First Angular App</h1>
Recipes - Simple Component with templateUrl
[[Link]]
...
beforeEach(async(() => {
[Link]({imports: [AppModule]});
// Precompile components with templateUrl.
[Link]();
}));
...
Recipes - Simple Component with templateUrl
[[Link]]
...
// Synchronous test method.
it('displays properly', () => {
let fixture = [Link](AppComponent);
[Link]();
expect([Link]).toBe("My First Angular App");
});
...
Recipes
Component communicating with backend service
Angular App
Component
Users Service
Backend
Recipes - Component Communicating with Backend service
beforeEach(async(() => {
[Link]({imports: [AppModule]});
// Override providers for the UsersService in the App module.
[Link](AppModule,
{set:
{providers: [{provide: UsersService, useClass: MockUsersService}]}
}
);
[Link]();
}));
Recipes - Component Communicating with Backend service
it('displays user details on click', async(() => {
...
// Locate the fetch button.
let debugFetchButton = [Link]([Link]('button'));
expect(debugFetchButton).[Link](null);
// Trigger the click event through the DOM.
[Link]();
...
}
Recipes - Component Communicating with Backend service
it('displays users list on click', async(() => {
...
// Wait for the async getUsers to complete and Angular to become stable.
[Link]().then(() => {
// Trigger rendering component state to DOM.
[Link]();
// Check that the user list is displayed.
...
}
}
Recipes - Component Communicating with Backend service
// fakeAsync() version.
it('displays user details on click(fakeAsync)', fakeAsync(() => {
...
// Trigger the click event through the DOM.
[Link]();
// Wait for Promise resolution and Angular to stabilize.
tick();
[Link]();
...
}
Recipes - Component Communicating with Backend service
import {XHRBackend} from '@angular/http';
import {MockBackend} from '@angular/http/testing';
...
// Setup for mocking the HTTP Backend.
beforeEach(() => {
[Link]({
imports: [HttpModule],
providers: [
UsersService,
{ provide: XHRBackend, useClass: MockBackend }
]
...
Recipes - Component Communicating with Backend service
it('returns all users', async(() => {
let backend = [Link](XHRBackend);
let http = [Link](Http);
let service = new UsersService(http);
let fakeUsers = makeUsers();
let options = new ResponseOptions({status: 200, body: fakeUsers});
let response = new Response(options);
[Link](
(c: MockConnection) => [Link](response));
[Link]().then(users => { ...
Recipes
Testing Application Routing
Recipes - Testing Application Routing
[Link]({
imports: [
[Link](ROUTES),
AppModule
]
});
Recipes - Testing Application Routing
// async version
[Link]('/about');
[Link]().then(() => {
[Link]();
// Verify we navigated to About page.
let desc = [Link]([Link]('.description'));
expect(desc).[Link](null);
expect([Link]).toContain('All about this sample');
});
Recipes - Testing Application Routing
// fakeAsync Version
[Link]('/about');
tick();
[Link]();
// Verify we navigated to About page.
let desc = [Link]([Link]('.description'));
expect(desc).[Link](null);
expect([Link]).toContain('All about this sample');
Recipes
Testing Nested Components
Recipes - Testing Nested Components
[[Link]]
<app-banner></app-banner>
<app-welcome></app-welcome>
<user-details></user-details>
Testing nested components - Approach 1
Don’t mock out anything
beforeEach(async(() => {
[Link]({imports: [AppModule]});
[Link]();
}));
Testing nested components - Approach 2
Mock all dependencies
...
[Link]({
declarations: [AppComponent, MockBannerComponent,
MockWelcomeComponent, MockUserDetailsComponent],
});
...
Testing nested components - Approach 3
Shallow Testing - NO_ERRORS_SCHEMA
...
[Link]({
declarations: [AppComponent],
schemas: [NO_ERRORS_SCHEMA],
});
...
WRITE UNIT TESTS!!
Resources
● [Link] Testing Guide
● Testing Angular 2 - Julie Ralph
● Three ways to test Angular 2 components
Acknowledgements
● Mashhood Rastgar, Gerard Sans - Ideas for the talk
● Jasmine Plunker template - Ken Rimple - @krimple
● Ward and the docs team for putting up the best docs
Thank You
Backup
Properties of good unit tests
● Fast
● Isolated
● Repeatable
● Self-verifying
● Timely
Source: [Link]