Skip to content

Testing

Gregor Woiwode edited this page Jun 22, 2016 · 2 revisions

Die angular-cli stellt uns ein fertige Testinfrastruktur zur Verfügung. Es kann zwischen 2 Testansätzen für Komponenten unterschieden werden.

  1. Für die Komponente kann ein Unit-Test geschrieben werden.
  2. Die Komponete kann in Verbindung mit ihrem Template getestet werden (Wir sprechen hier von einem Integrationstest).

Unit-Test

Für den Test müssen wir aus dem Angular Testing-Namespace die Funktionen beforeEachProviders, describe, expect und it laden. Des Weiteren benötigen wir die zu Testende Komponente (hier: BookComponent), sowie Klassen, die diese Komponente nutzt (Bsp.: Book).

Mithilfe von beforeEachProviders wird die zu testende Komponente dem Test-Injector bekannt gemacht. Danach können wir die API-Komponente testen.

import { beforeEachProviders, describe, expect, it } from '@angular/core/testing';

import {BookComponent} from './book.component';
import {Book} from '../shared';

describe('Rate a book', () => {
  beforeEachProviders(() => [BookComponent]);

  it('should increase the rating by one', () => {
    let component = new BookComponent();

    component.book = new Book('title', 'description');
    component.rateUp();

    expect(component.book.rating).toBe(1);
  });
});

Integrationstest

Möchte man ebenfalls das Template in den Test einbeziehen wird das Test-Setup komplexer. Der Grund ist, dass die Komponente samt Template im Test gerendered werden muss.

Als erstes wird ein Konsument benötigt der die zu testende Komponente lädt. Die imports ComponentFixture, TestComponentBuilder, provide, By benötigen wir im Anschluss, um die Instanz der Komponente zu erstellen.

// ... import beforeEach, etc.
import { ComponentFixture,  } from '@angular/compiler/testing';
import { provide } from '@angular/core';
import {  } from '@angular/platform-browser';

@Component({
  selector: 'test',
  template: `
    <br-dashboard></br-dashboard>
  `,
  directives: [DashboardComponent]
})
class DashboardComponentTestController { }

Um die Komponente instanziieren zu können, muss der TestComponentBuilder bereitgestellt werden. Damit wir den Code für TestComponentBuilder nicht für jeden Test aufs neue schreiben müssen, nutzen wir den Hook beforeEach. Dieser wird vor jedem Test ausgeführt. Eine Referenz des TestComponentBuilder speichern wir im Feld builder.

describe('DashboardComponent', () => {
    let builder: TestComponentBuilder;

    beforeEach(inject([TestComponentBuilder], function (tcb: TestComponentBuilder) {
      builder = tcb;
    }));
});

Nun ist es möglich die Komponente inkl. Template zu erstellen. Zum einen erhalten wir eine Instanz von ComponentFixture<T> und speichern sie im Feld fixture. fixture einen Kontext bereit, aus dem wir die gewünschte Komponente, abrufen können. Des Weiteren können Aktionen im Template ausgeführt werden (Formular befüllen, Buttons klicken, ...).

Übrigens Enthalt eine Komponente mehrere Kindkompoenten können diese auch über die ComponentFixture<T> aufgelöst werden.

describe('...', () => {
    let builder: TestComponentBuilder;
    // beforeEach -> TestComponentBuilder

    describe('Rating a book', () => {
        let fixture: ComponentFixture<Dasboard>;
        let dashboard: DashboardComponent;

        beforeEach(() => {
          return builder
            .createAsync(DasboardTestController)
            .then((_fixture_: ComponentFixture<Dasboard>) => {
              fixture = _fixture_;

              control = new FixtureControl(fixture);

              dashboard = fixture
                            .debugElement
                            .query(By.directive(Dasboard))
                            .componentInstance;

              dashboard.ngOnInit();
            });
        });
    });
});

Schließlich sind wir in der Lage den Test zu schreiben. Wir nutzen klassische CSS-Selektoren um die Controls des Templates zu steurn.

describe('Rating a book', () => {
    it('creates a new of the book', () => {
      fixture.nativeElement.querySelector('input.form-control[name="title"]')
             .setAttribute('value', 'Angular 2');

      fixture.nativeElement.querySelector('textarea.form-control[name="comment"]')
             .innerHTML = 'Workshop';

      fixture.nativeElement.querySelector('button.btn.btn-danger')
             .dispatchEvent(new Event('click'));

      expect(dashboard.books.length).toEqual(3);
    });
});

Clone this wiki locally