2016-11-08 62 views
1

我有一個Angular 2服務的方法,它獲取特定用戶帳戶的所有詳細信息 - 登錄的帳戶 - 並返回一個Observable。Angular 2 Observable and Promise回調單元測試

(我使用AngularFire2進行身份驗證,爲它的價值)

正如你所看到的,getData方法是使用getAuth方法,該方法返回認證狀態(如可觀察到的),這反過來又由getToken方法(它返回一個Promise)使用來獲取用於填充Authorization標頭並執行http請求的令牌。 (我也明白,我的代碼可能需要重構,我將不勝感激任何意見)

getData(): Observable<IData> { 
    let authHeaders = new Headers(); 

    return Observable.create((o: Observer<IData>) => { 
     this.getAuth().subscribe((authState: IState) => { 
      this.getToken(authState).then(token => { 
       /* ... 
       * Do things with that token, call an http service etc. 
       */ ... 
       authHeaders.set('Authorization', token); 

       this.http.get('myendpoint/', { 
        headers: this.authHeaders 
       }) 
       .map((response: Response) => response.json()) 
       .map((data: IData) => { 
        o.next(data); 
       }); 
      }) 
      .catch((error: Error) => { 
       Observable.throw(new Error(`Error: ${error}`)); 
      }); 
     }); 
    }); 
} 

我是新來的單元測試,並已試圖測試這種方法,但我仍然不能掩蓋該方法中的Promise的.catch

這裏是我的單元測試的樣子:

describe('Service: UserDataService',() => { 
    let mockHttp: Http; 
    let service: UserDataService; 
    let getAuthSpy: jasmine.Spy; 
    let getTokenSpy: jasmine.Spy; 

    beforeEach(() => { 
     mockHttp = { get: null } as Http; 

     TestBed.configureTestingModule({ 
      providers: [ 
       { provide: Http, useValue: mockHttp }, 
       AngularFire, 
       UserDataService, 
      ] 
     }); 

     service = new UserDataService(AngularFire, mockHttp); 

     spyOn(mockHttp, 'get').and.returnValue(Observable.of({ 
      json:() => { 
       "nickname": "MockNickname" 
      } 
     })); 

     getAuthSpy = spyOn(service, 'getAuth').and.returnValue(Observable.of({ 
      "auth": { 
      "uid": "12345" 
     })); 

     getTokenSpy = spyOn(service, 'getToken').and.returnValue(new Promise((resolve, reject) => { 
      resolve('test promise response'); 
     })); 
    }); 

    describe('getLead',() => { 
     beforeEach(() => { 
      spyOn(service, 'getLead').and.callThrough(); 
     }); 

     it('should return an object of user data and set the dataStore.userEmail if state exists',() => { 
      service.getLead().subscribe(res => { 
       expect(res).toEqual(jasmine.objectContaining({ 
        nickname: 'MockNickname' 
       })); 
      }); 

      expect(service.getLead).toHaveBeenCalled(); 
     }); 

     it('should throw, if no authState is provided',() => { 
      getAuthSpy.and.returnValue(Observable.of(false)); 

      service.getLead(); 

      expect(service.getLead).toThrow(); 
     }); 

     it('should throw, if getToken() fails to return a token',() => { 
      getTokenSpy.and.returnValue(new Promise((resolve, reject) => { 
       reject('test error response'); 
      })); 

      /* 
      * This is where I am getting lost 
      */ 

      service.getLead(); 

      expect(service.getLead).toThrow(); 
     }); 
    }); 
}); 

從我明白我必須以某種方式作出這樣的承諾,從getToken拒絕,並測試,看看我觀察到會拋出。

任何幫助或反饋非常感謝。

+0

'spyOn(...)。and.returnValue(Observable.throw(...)。toPromise())'?你可以用'Observable.map'使這個更加線性化,逐步執行,而不是增加嵌套,根據需要轉換'fromPromise'和'toPromise'。 – jonrsharpe

回答

1

我沒有使用jasmine也沒有使用AngularFire2,所以我不能告訴你到底要做什麼,但是從你的代碼中,很明顯this.getToken(authState)返回Promise

問題來自於什麼庫這個Promise類來自(也就是你正在使用什麼polyfill)。

據我所知,Promises/A的實現應該用try-catch來包裝回調函數,所以如果then(...)中的回調拋出Promise將傳播到catch()的異常。所以我想你可以假裝this.http.get('myendpoint/')的響應與一些格式不正確的JSON,將導致在response.json()錯誤。

第二件事是catch()內回調:

.catch((error: Error) => { 
    Observable.throw(new Error(`Error: ${error}`)); 
}); 

這確實幾乎一無所有。有沒有返回聲明和Observable.throw()需要出現在Observable鏈內做些事情。請注意,這個.catch()方法來自您的Promise類,而不是來自Observable。

如果你想讓它實際上是傳播錯誤觀察員,那麼你必須顯式調用:

.catch((error: Error) => { 
    o.error(error); 
}); 

也許如果錯誤冒泡到Observable.create()將它傳遞給觀察者好了,我我不確定這一點。

0

我有我類似的問題,然後我用Observable.from:

spyOn(service, 'function').and.returnValue(Observable.fromPromise(Promise.reject({}))); 

您返回無極裏面的錯誤。拒絕