2017-07-17 7 views
0

Als Teil eines Angular 4 Projekts versuche ich verzweifelt, mit Jasmine eine Funktion zu testen, die eine RxJs Kette/Sequenz mit Operatoren implementiert (map in meinem Fall).Angular2/RxJS/Jasmine: Wie zu testen Observable Kette/Sequenz (Operatoren)

class RendezVousResolver { 

    searchRendezVous(code: string): Observable<any> { 
    return Observable.create(observer => { 
     this.userCardService.readCard(code).map(userData => { 
     this.rendezVousService.search(userData).subscribe(
      result => { 
      observer.next(result); 
      }, 
      error => { 
      observer.error(error); 
      } 
     ); 
     }); 
    }); 
    } 

} 

My Unit-Test verwendet 2 Mocks, um "zu simulieren", um die 2-Dienste Schichten: userCardService und rendezVousService.

class MockUserCardService { 

    readCard(code: string): Observable<any> { 
    return Observable.of('<data></data>'); 
    } 

} 

class MockRendezVousService { 

    search(userData : string): Observable<any> { 
    return Observable.of({ 
     rdvs: [] 
    }); 
    } 

} 

beforeEach(() => { 
    TestBed.configureTestingModule({ 
    providers: [ 
     RendezVousResolver, 
     { provide: RendezVousService, useClass: MockRendezVousService }, 
     { provide: SwcVitaleReadingService, useClass: MockSwcVitaleReadingService } 
    ] 
    }); 
    fixture = TestBed.get(RendezVousResolver); 
}); 

Und hier meine Einheit testen.

Wenn ich es ausführe, scheint der Test nicht auf die Ereignisse zu warten, die von dem verspotteten Observable ausgegeben werden. Weder die expected noch die fail werden ausgeführt. Da bin ich mir sicher, da nichts in der Konsole geloggt wird.

Die einzige Möglichkeit, diesen Test bestanden zu haben, ist, den Operator map nicht zu verwenden und meinen Code durch verschachtelte Subskriptionen zu ersetzen.

searchRendezVous(code: string): Observable<any> { 
    return Observable.create(observer => { 
    this.userCardService.readCard(code).subscribe(
     userData => { 
     this.rendezVousService.search(userData).subscribe(
      rdvs => { 
      observer.next(rdvs); 
      }, 
      error => { 
      observer.error(error); 
      } 
     ) 
     }, 
     error => { 
     observer.error(error); 
     } 
    ); 
    }); 
} 

begegnete ich das gleiche Problem mit anderen Betreibern als map (zip zum Beispiel).

Vielen Dank für Ihre Hilfe.

+0

einen Blick auf diese https://stackoverflow.com/questions/42732988/how-do-i-test-a-function-that-returns-an-observable-using-timed-intervals-in -rxj/42734681 # 42734681 – martin

+0

Ohne Bezug zu testen, aber diese Anrufe, die Sie zu "Observable.create" machen, sind etwas von einem Antipattern. Vielleicht möchten Sie Folgendes beachten: https://egghead.io/courses/save-time-avoiding-common-mistakes-using-rxjs – cartant

+0

Der einfachste Weg, wenn Sie viele asynchrone Operationen haben, ist die Done-Funktion, schauen Sie für jasmine.done auf dieser Seite https://angular.io/guide/testing – gropapa

Antwort

1

können Sie vereinfachen Ihre RendezVousResolver durch Observable.create für bestehende Verhalten/Funktionen in RxJs Swapping:

class RendezVousResolver { 
    searchRendezVous(code: string): Observable<any> { 
    return this.userCardService.readCard(code) 
     .mergeMap(userData => this.rendezVousService.search(userData)); 
    } 
} 

diese Weise werden Sie weniger Grenzfälle haben sich zu fangen.

Das Testen kann ohne Zeit durchgeführt werden, indem die readCard und search mit Mocks ausgetauscht werden, die eine Rx.Observable.from([]) mit den erwarteten Scheindaten zurückgeben. Einfaches Aufrufen von .toPromise() auf Ihrem searchRendezVous() wird dies ohne Scheduler Magie machen.

it('returns data',() => { 
    return searchRendezVous('foo') 
    .toPromise() 
    .then(searchResults => { 
     expect(searchResults).to.not.be.empty();//assert what you need 
    }) 
});