Testowanie elementów z zależnościami
W poprzednim przykładzie testowaliśmy prosty serwis LocalStoragePrefixService, który nie korzystał z narzędzi dostarczanych przez framework Angular - mogliśmy testować go w całkowitej izolacji. Co w momencie, gdy nasz moduł jednak z takich narzędzi korzysta?
Przykładowy serwis korzystający z wbudowanego serwisu do wykonywania zapytań HTTP:
import { Observable } from 'rxjs/Observable';
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import "rxjs/add/operator/map";
const BASE_API_URL = 'https://api.punkapi.com/v2/';
@Injectable()
export class RestClientService {
constructor (
private _http: Http
) { }
public get (url): Observable<any> {
return this._http
.get(`${BASE_API_URL}${url}`)
.map((res: Response) => res.json());
}
}
Aby móc przetestować należy skorzystać ze specjalnej klasy MockBackend zastępującej XHRBackend jak w poniższym przykładzie:
import { TestBed, inject} from '@angular/core/testing';
import { HttpModule, Response, ResponseOptions, XHRBackend } from '@angular/http';
import { MockBackend } from '@angular/http/testing';
import { RestClientService } from './rest-client.service';
describe('RestClientService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [
RestClientService,
{provide: XHRBackend, useClass: MockBackend},
]
});
});
describe('get()', () => {
it('should return an Observable of objects',
inject([RestClientService, XHRBackend], (restClient, mockBackend) => {
const mockResponse = [
{
id: 185,
name: "Tactical Nuclear Penguin",
brewers_tips: "This level of alcohol can be achieved using a domestic freezer. Use a container with a tap close to the bottom so you can run the un-frozen, concentrated beer from under the ice on top. You may have to do this three or four times.",
contributed_by: "Sam Mason <samjbmason>"
},
{
id: 186,
name: "Jasmine IPA",
brewers_tips: "When dry hopping with the jasmine, use a muslin or cloth like a tea bag, and make sure it has a heavy object in it (ensure its clean). This will help to keep the jasmine submerged in the beer for better flavour extraction.",
contributed_by: "Sam Mason <samjbmason>"
}
];
mockBackend.connections.subscribe((connection) => {
connection.mockRespond(new Response(new ResponseOptions({
body: JSON.stringify(mockResponse)
})));
});
restClient.get().subscribe((beers) => {
expect(beers.length).toBe(2);
expect(beers[0].id).toBe(185);
expect(beers[0].name).toBe('Tactical Nuclear Penguin');
expect(beers[1].id).toBe(186);
expect(beers[1].name).toBe('Jasmine IPA');
});
}));
});
});
Testowanie komponentów z zależnościami
Jeżeli posiadamy komponent, którego zależnością jest serwis w większości przypadków będziemy musieli podmienić realny obiekt na jego imitacje.
Przykładowy komponent posiadający opisaną zależność:
import { Component, OnInit } from '@angular/core';
import { Beer } from '../../shared/model/beer';
import { BeerService } from '../../shared/service/beer.service';
@Component({
selector: 'app-random-beer',
templateUrl: './random-beer.component.html',
styleUrls: ['./random-beer.component.css']
})
export class RandomBeerComponent implements OnInit {
public beer: Beer;
constructor (
private _beer: BeerService
) {}
ngOnInit () {
this._beer.getRandomBeer().subscribe(beer => {
this.beer = beer;
});
}
}
Test z użyciem imitacji serwisu BeerService wyglądać może następująco:
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import {RandomBeerComponent} from './random-beer.component';
import {BeerService} from '../../shared/service/beer.service';
import "rxjs/add/observable/of";
import {Observable} from "rxjs/Observable";
import {Beer} from "../../shared/model/beer";
import {RestClientService} from "../../shared/service/rest-client/rest-client.service";
import {MockBackend} from '@angular/http/testing';
import {Http} from "@angular/http";
class MockBeerService extends BeerService {
public getRandomBeer(): Observable<Beer> {
return Observable.of({});
}
}
describe('RandomBeerComponent', () => {
let component: RandomBeerComponent;
let fixture: ComponentFixture<RandomBeerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [RandomBeerComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [
{provide: BeerService, useClass: MockBeerService},
RestClientService,
{provide: Http, useClass: MockBackend}
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(RandomBeerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});