Components are everywhere in our apps and testing them is part of our daily software development process.
But here are some good news: Testing should not be hard!
There are 3 types of tests for our Components:
- Isolated (fastest)
- Shallow (fast)
- Deep (not so fast)
In this tutorial we will explore Isolated tests
Isolated Tests
Those are the less utilized tests in Angular testing yet the most fast and simple to use.
In those kinds of tests we treat the Component as a simple class.
Testing classes is easy, we can call their methods and verify the results.
Note that we just test the class functionality and NOT anything in the DOM.
Case 1 (simple) the component has no dependencies
Here is our component:
// explorer.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-explorer',
templateUrl: './explorer.component.html',
styleUrls: ['./explorer.component.scss']
})
export class ExplorerComponent implements OnInit {
explorerName: string;
location: string;
constructor() { }
ngOnInit() {
}
getLocation(location) {
this.location = `Your location is ${location}`;
}
}
Here we perform tests:
// explorer.component.spec.ts
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ExplorerComponent } from './explorer.component';
describe('Isolated ExplorerComponent Tests', () => {
let component: ExplorerComponent;
beforeEach(() => {
component = new ExplorerComponent();
});
it('should set the correct location', () => {
component.getLocation('Mars');
expect(component.location).toContain('Mars');
});
});
We can test it just like any other class!
Case 2 : the component has dependencies
here is our service:
// explorer.service.ts
import { Injectable } from '@angular/core';
import { of } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ExplorerService {
constructor() { }
getExplorer() {
return of('Josh the Lost');
}
getLocation() {
return 'The dark side of the moon';
}
}
our component:
// explorer.component.ts
import { Component, OnInit } from '@angular/core';
import { ExplorerService } from './services/explorer.service';
@Component({
selector: 'app-explorer',
templateUrl: './explorer.component.html',
styleUrls: ['./explorer.component.scss']
})
export class ExplorerComponent implements OnInit {
explorerName: string;
location: string;
constructor(
private explorerService: ExplorerService
) { }
ngOnInit() {
this.explorerService.getExplorer().subscribe(data => {
this.explorerName = data;
});
}
getLocation(location) {
this.location = `Your location is ${location}`;
}
}
our tests:
// explorer.component.spec.ts
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ExplorerComponent } from './explorer.component';
import { of } from 'rxjs';
describe('Isolated ExplorerComponent Tests', () => {
let component: ExplorerComponent;
// create a spyObject to simplify our mock service creation
const mockExplorerService = jasmine.createSpyObj(['getExplorer']);
// set the getExplorer method to return an Observable just like the real one
mockExplorerService.getExplorer.and.returnValue(of('Dave the brave'));
beforeEach(() => {
component = new ExplorerComponent(mockExplorerService);
});
it('should set the correct location', () => {
component.getLocation('Mars');
expect(component.location).toContain('Mars');
});
it('should set the correct explorer', () => {
// trigger
component.ngOnInit();
expect(component.explorerName).toEqual('Dave the brave');
// verify that getExplorer from the service has been called
expect(mockExplorerService.getExplorer).toHaveBeenCalled();
});
});
Conclusion
Using Isolated tests we can test functionality with a simple way that is performant and easy to understand.
Note that this approach is great for testing just the component (class) code and is not meant to replace TestBed in any way.
We can just combine different kinds of tests to compliment our testing efforts :)
Happy testing !!!
Photo by Rodolfo Clix from Pexels
Top comments (0)