2017-07-17 84 views
0

作爲Angular 4項目的一部分,我拼命嘗試用Jasmine測試一個函數,該函數實現了一個帶有運算符的RxJs鏈/序列(map案件)。Angular2/RxJS/Jasmine:如何測試Observable鏈/序列(運算符)

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); 
      } 
     ); 
     }); 
    }); 
    } 

} 

我的單元測試使用2個嘲笑以「模擬」的服務2層:userCardServicerendezVousService

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); 
}); 

在這裏我的單元測試。

it('should return the expected response', async(() => { 
    fixture.resolve(undefined, undefined).subscribe(
    rdvs => { 
     console.log("expect"); 
     expect(rdvs).toEqual({ 
     rdvs: [] 
     }); 
    }, 
    error => { 
     console.log("fail"); 
     fail('No error was expected'); 
    } 
); 
})); 

當我執行它時,測試似乎不等待模擬的Observable發出的事件。 expectedfail都沒有執行。我很確定,因爲控制檯中沒有記錄任何內容。

我發現通過此測試的唯一方法是不要使用運算符map並用嵌套訂閱替換我的代碼。

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); 
     } 
    ); 
    }); 
} 

與他人運營商遇到同樣的問題比mapzip爲例)。

謝謝你的幫助。

+0

看一看這個https://stackoverflow.com/questions/42732988/how-do-i-test-a-function-that-returns-an-observable-using-timed-intervals-in -rxj/42734681#42734681 – martin

+0

與測試無關,但您對「Observable.create」進行的調用是反模式。您可能需要考慮觀察以下內容:https://egghead.io/courses/save-time-avoiding-common-mistakes-using-rxjs – cartant

+0

當您有許多異步操作時,最簡單的方法是使用done函數,對於此頁上的jasmine.done https://angular.io/guide/testing – gropapa

回答

1

您可以簡化您在RxJs交換Observable.create現有的行爲/功能RendezVousResolver

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

你有較少的邊緣情況下發現自己的方式。

通過將readCardsearch與模擬返回Rx.Observable.from([])與預期的模擬數據進行交換,可以毫無時間地完成測試。只需在您的searchRendezVous()上調用.toPromise()即可使這項工作無任何調度魔術。

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