Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 32

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

[app.component.ts]
@Component({
moduleId: module.id,
selector: 'my-app',
templateUrl: 'app.component.html'
})
export class AppComponent {}

[app.component.html]
<h1>My First Angular App</h1>
Recipes - Simple Component with templateUrl

[app.component.spec.ts]
...
beforeEach(async(() => {
TestBed.configureTestingModule({imports: [AppModule]});

// Precompile components with templateUrl.


TestBed.compileComponents();
}));
...
Recipes - Simple Component with templateUrl

[app.component.spec.ts]
...
// Synchronous test method.
it('displays properly', () => {
let fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
expect(fixture.nativeElement.textContent).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(() => {
TestBed.configureTestingModule({imports: [AppModule]});

// Override providers for the UsersService in the App module.


TestBed.overrideModule(AppModule,
{set:
{providers: [{provide: UsersService, useClass: MockUsersService}]}
}
);
TestBed.compileComponents();
}));
Recipes - Component Communicating with Backend service

it('displays user details on click', async(() => {


...
// Locate the fetch button.
let debugFetchButton = fixture.debugElement.query(By.css('button'));
expect(debugFetchButton).not.toBe(null);

// Trigger the click event through the DOM.


debugFetchButton.nativeElement.click();
...
}
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.
fixture.whenStable().then(() => {
// Trigger rendering component state to DOM.
fixture.detectChanges();

// 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.
debugFetchButton.nativeElement.click();

// Wait for Promise resolution and Angular to stabilize.


tick();

fixture.detectChanges();
...
}
Recipes - Component Communicating with Backend service

import {XHRBackend} from '@angular/http';


import {MockBackend} from '@angular/http/testing';
...
// Setup for mocking the HTTP Backend.
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [
UsersService,
{ provide: XHRBackend, useClass: MockBackend }
]
...
Recipes - Component Communicating with Backend service

it('returns all users', async(() => {


let backend = TestBed.get(XHRBackend);
let http = TestBed.get(Http);
let service = new UsersService(http);
let fakeUsers = makeUsers();
let options = new ResponseOptions({status: 200, body: fakeUsers});
let response = new Response(options);

backend.connections.subscribe(
(c: MockConnection) => c.mockRespond(response));

service.getUsers().then(users => { ...


Recipes

Testing Application Routing


Recipes - Testing Application Routing

TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes(ROUTES),
AppModule
]
});
Recipes - Testing Application Routing

// async version
router.navigateByUrl('/about');

fixture.whenStable().then(() => {
fixture.detectChanges();

// Verify we navigated to About page.


let desc = fixture.debugElement.query(By.css('.description'));
expect(desc).not.toBe(null);

expect(desc.nativeElement.textContent).toContain('All about this sample');


});
Recipes - Testing Application Routing

// fakeAsync Version
router.navigateByUrl('/about');

tick();
fixture.detectChanges();

// Verify we navigated to About page.


let desc = fixture.debugElement.query(By.css('.description'));
expect(desc).not.toBe(null);
expect(desc.nativeElement.textContent).toContain('All about this sample');
Recipes

Testing Nested Components


Recipes - Testing Nested Components

[app.component.html]

<app-banner></app-banner>
<app-welcome></app-welcome>
<user-details></user-details>
Testing nested components - Approach 1

Don’t mock out anything


beforeEach(async(() => {
TestBed.configureTestingModule({imports: [AppModule]});
TestBed.compileComponents();
}));
Testing nested components - Approach 2

Mock all dependencies


...
TestBed.configureTestingModule({
declarations: [AppComponent, MockBannerComponent,
MockWelcomeComponent, MockUserDetailsComponent],
});
...
Testing nested components - Approach 3

Shallow Testing - NO_ERRORS_SCHEMA


...
TestBed.configureTestingModule({
declarations: [AppComponent],
schemas: [NO_ERRORS_SCHEMA],
});
...
WRITE UNIT TESTS!!
Resources

● Angular.io 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: https://pragprog.com/magazines/2012-01/unit-tests-are-first

You might also like