2016-11-08 52 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({}))); 

您返回无极里面的错误。拒绝