2016-05-21 10 views
2

Ich schreibe gerade Komponententests für eine meiner Komponenten. Insbesondere habe ich login(): void Funktion. Hier ist die vereinfachte Logik:Angular2-Testlogik vor .subscribe

login(): void { 
    this.showSpinner = true; 
    this.userService.login(loginData) 
    .subscribe(result => { 
     this.showSpinner = false; 
    } 
) 
} 

Ich kämpfe um einen Test zu schreiben, die überprüft, ob showSpinner Eigenschaft auf true gesetzt wird, bevor die userService.login aufrufen.

Hier ist mein Test:

it('should display the spinner when the form is being saved', 
    inject([TestComponentBuilder], fakeAsync((tcb: any) => { 
    createComponent(tcb).then((fixture:ComponentFixture<any>) => { 
     fixture.componentInstance.login(); 
     expect(fixture.componentInstance.showSpinner).toBe(true); 
     tick(); 
    }); 
    }))); 
}); 

Und dieser Test fehlschlägt, weil .subscribe gelöst wird/laufen sofort (ich versuchte this.showSpinner = false in meiner Komponente zu kommentieren, und der Test bestanden).

In meinem userService Mock, ich habe folgendes für die login Mock-Methode: mockUserService

this.loginSpy = this.spy('login').andReturn(Observable.of(this));

Wo this ist.

Ich bin zuversichtlich, dass ich mich und speziell die login Methode auf dem richtig mokieren, da ich andere Tests für diese Komponente habe, die sich korrekt verhalten.

Ich habe auch versucht, Observable.of(this).delay(1) von meinem Spion und dann Aufruf tick(1) in meinem Test. Jedoch, dass die Ergebnisse in inkonsistentes Verhalten, dass manchmal passieren meinen Tests, aber auch andere Zeiten bekomme ich eine Fehlermeldung,:

Error: 1 periodic timer(s) still in the queue.

Wie kann ich die Logik testen, die .subscribe() vorangeht?

Antwort

0

Nach mehr Überlegung habe ich festgestellt, dass mein derzeitiger Code nicht das Prinzip der einfachen Verantwortung befolgt. Dieser Gedanke kam von der Tatsache, dass jeder immer wieder wiederholt, dass man "schwer Code testen sollte".

In diesem Sinne habe ich alle Logik, die getan werden musste, bevor der Anruf an userService.login gemacht wird - in seine eigene separate Funktion verschoben. Welche ergibt sich im Wesentlichen in:

login():void { 
    this.userService.login(this.loginData) 
    .subscribe(result => { 
     this.showSpinner = false; 
    }); 
} 

formSubmit(): void { 
    this.showSpinner = true; 
    this.login(); 
} 

Diese Logik jetzt viel einfacher zu testen ist.

JEDOCH müssen wir daran denken, einen Spion auf unsere login() Methode hinzufügen, wenn wir formSubmit() testen, als ob wir nicht, formSubmit() einfach einen Anruf zu login() machen, die wieder synchron beenden, und wir haben Dasselbe Problem. Also mein neuer und letzter Test für diese Funktion ist:

it('should display the spinner when the form is being saved', 
    inject([TestComponentBuilder], fakeAsync((tcb: any) => { 
    createComponent(tcb).then((fixture:ComponentFixture<any>) => { 
     var loginSpy = spyOn(fixture.componentInstance, 'login'); 
     fixture.componentInstance.formSubmit(); 
     expect(fixture.componentInstance.showSpinner).toBe(true); 
    }); 
    }))); 
});