

Angular Testing
Jesús Rodríguez
Foxandxss
Agenda
- Un pequeño repaso...
- UNIT testing y mocks.
- TestBed.
- Testeando componente.
- Testeando servicio.
- Testeando tubería.
- Ejemplo real.
Un pequeño repaso...
En Angular tenemos los NgModule:
@NgModule({
imports: [ BrowserModule, HttpModule ],
declarations: [ AppComponent, TeamsComponent, CapitalizePipe ],
providers: [ TeamService ],
bootstrap: [ AppComponent ]
})
export AppModule {}Que es como una caja donde registramos las distintas piezas de nuestra aplicación...
UNIT testing y mocks
La regla de oro de los unit test, es que una unidad (unit) tiene que ser testeada sin necesitar ninguna de sus dependencias.
class TeamServiceSpy {
getTeams = jasmine.createSpy('getTeams').and.callFake(() => {
return Observable.of([{ id: 0, name: 'Madrid'}, { id: 1, name: 'Malaga' }]);
});
}Un ejemplo de mock de un servicio sería:
Eso quiere decir, que si una unidad tiene dependencias, tenemos que reemplazarlas por mocks.
TestBed
En testing, tenemos nuestros propios NgModule:
TestBed.configureTestingModule({
imports: [ ... ],
declarations: [ ... ],
providers: [ ... ],
...
});Nuestra propia caja vacía que podemos configurar como necesitemos.
TestBed es la utilidad principal de Angular para escribir nuestros tests.
Testeando componente
Tenemos un componente TeamsComponent que inyecta TeamService como dependencia y muestra un listado de equipos:
@Component({
selector: 'gr-teams',
template: `
<ul>
<li *ngFor="let team of teams">
{{team.id}} - {{team.name}}
</li>
</ul>
`
})
export class TeamsComponent implements OnInit {
teams: any;
constructor(private teamService: TeamService) { }
ngOnInit() {
this.teamService.getTeams().subscribe(teams => this.teams = teams);
}
}Testeando componente
Lo primordial es coger ese módulo, esa caja vacía y darle lo mínimo que nos hace falta, TeamsComponent y un mock de TeamService.
TestBed.configureTestingModule({
declarations: [ TeamsComponent ],
providers: [ ¿ ? ]
});¿Qué ponemos en provider? No podemos poner el original y si le damos el mock no sabrá para qué.
providers: [{ provide: TeamService, useClass: TeamServiceSpy }]Testeando componente
Una vez tenemos el módulo configurado, creamos el componente:
let fixture: ComponentFixture<TeamsComponent>;
fixture = TestBed.createComponent(TeamsComponent);Y guardamos una referencia a la instancia en si:
let instance: TeamsComponent;
instance = fixture.componentInstance;Por último, vamos a pedirle al inyector la instancia del servicio:
let teamService: TeamService;
teamService = fixture.debugElement.injector.get(TeamService);
Testeando componente
Al ejecutar ngOnInit, ¿está recibiendo los equipos?
it('fetches all teams', () => {
instance.ngOnInit();
expect(instance.teams.length).toBe(2);
expect(teamService.getTeams).toHaveBeenCalled();
});¿Y los muestra por pantalla?
it('renders the teams on the screen', () => {
fixture.detectChanges();
const li = fixture.debugElement.queryAll(By.css('li'));
expect(li.length).toBe(2);
});Testeando componente
Como alternativa, se puede usar un componente de prueba que haga de wrapper al componente bajo test.
@Component({
selector: 'gr-test',
template: '<gr-team [home]="home"></gr-team>'
})
class TestComponent {
home = { id: 0, name: 'Malaga' };
}Gracias a este wrapper, podríamos testear la API (entradas y salidas) de nuestro componente.
Testeando servicio
Supongamos que tenemos el siguiente servicio:
export class TeamService {
constructor(private http: Http) { }
getTeams() {
return this.http.get('api/teams')
.map((res) => res.json().data);
}
getTeam(id: number) {
return this.http.get(`api/teams/${id}`)
.map((res) => res.json().data);
}
}Testeando servicio
¿Cómo hacemos mock de HTTP?
providers: [
TeamService,
{
provide: Http,
useFactory: (backend, options) => {
return new Http(backend, options);
},
deps: [MockBackend, BaseRequestOptions]
},
MockBackend,
BaseRequestOptions
]Testeando Servicio
Inyectando nuestras dependencias antes de cada test:
beforeEach(inject([TeamService, MockBackend],
(service: TeamService, backend: MockBackend) => {
showService = service;
mockBackend = backend;
fakeTeams = {
data: [
{ id: 0, name: 'Malaga' },
{ id: 1, name: 'Madrid' }
]
};
}));Y creando algunos equipos de ejemplo...
Testeando Servicio
... que habría que proveer cuando hagan falta.
it('gets the list of shows', () => {
mockBackend.connections.subscribe((connection) => {
connection.mockRespond(new Response(new ResponseOptions({
body: JSON.stringify(fakeTeams)
})));
});
showService.getShows().subscribe((shows) => {
expect(shows.length).toBe(2);
expect(shows[0].name).toBe('Malaga');
expect(shows[1].name).toBe('Madrid');
});
});Testeando tuberías
Y sin TestBed ;)
describe('CapitalizePipe', () => {
let pipe = new CapitalizePipe();
it('capitalizes "angular is nice"', () => {
expect(pipe.transform('angular is nice')).toBe('Angular is nice');
});
it('capitalizes the entire sentence', () => {
expect(pipe.transform('angular is nice', true)).toBe('Angular Is Nice');
});
});import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'capitalize'})
export class CapitalizePipe implements PipeTransform {
transform(value: string) {
return value[0].toUpperCase() + value.substring(1);
}
}Usando by
Para testeo de componentes, tenemos acceso a By:
import { By } from '@angular/platform-browser';fixture.debugElement.query(By.css('foo'));
fixture.debugElement.queryAll(by.directive('directive'));
GRACIAS
Angular testing
By Jesus Rodriguez
Angular testing
- 457