2016-02-26 141 views
7

我想測試訂閱從服務中的方法返回的observable的Angular 2組件中的方法。下面是在總結服務方法的代碼:測試訂閱observable的方法 - Angular 2

public create(user: User): Observable<any> { 
    return this.http.post(this._api.create, 
    JSON.stringify(user), { 
     headers: this.apiConfig.getApiHeaders() 
    }).map((res: Response) => res.json()); 
    } 

很容易單元測試這種方法,因爲它返回一個可觀察的,所以我可以只訂閱。但我想測試的方法在已經訂閱了這個組件:

public onSubmit(user: User): void { 
    this._authentication.create(user).subscribe((token) => { 
    localStorage.setItem('token', token); 
    this.router.navigate(['/Home']); 
    }); 
} 

我的繼承人規範,到目前爲止,但是當我嘗試spyOn的localStorage.setItem它回來不會被調用。我的理解是它可能會檢查它是否在實際調用之前被調用。

it('Should login a user and on success store a token in localStorage', 
    injectAsync([TestComponentBuilder], (tcb) => { 
    return tcb.createAsync(Login).then((fixture) => { 
     let instance = fixture.debugElement.componentInstance; 
     localStorage.clear(); 
     spyOn(localStorage, 'setItem'); 
     instance.onSubmit({userId: '[email protected]', password: 'password', siteName: 'sample'}); 
     expect(localStorage.setItem).toHaveBeenCalled(); 
    }); 
    }) 
); 

我想知道如果我需要模擬出this._authentication.create方法返回一個新的觀察到的,在這一個模擬的反應?

經過更多的研究,一些文章指出我需要嘲笑服務並返回一個同步運行的Observable.of()來解決問題,請仔細複製下面的代碼。然而,這仍然不起作用,我一直在這一天的大部分時間裏工作,我不覺得這應該是那麼辛苦,任何幫助表示讚賞。

class MockAuthentication extends Authentication { 
    public create(user: Object): Observable<any> { 
    return Observable.of({'test': 'test'}); 
    } 
} 

回答

2

好的,這是我一天中的大部分時間,但我終於破解了它。而不是使用injectAsync和TestComponentBuilder來設置規範,我只需要像使用服務一樣使用注入和注入組件。這看起來很好,因爲我不需要在視圖中像事件一樣測試任何東西。

繼承人的最終規格,做工作:

it('Should set token in localStorage, set the new user, 
and navigate to home page on succesful login', 
    inject([Login], (login) => { 
    login.router.config([ { path: '/', name: 'Home', component: Home }]); 
    spyOn(localStorage, 'setItem'); 
    spyOn(login._currentUser, 'set'); 
    spyOn(login.router, 'navigate'); 
    login.onSubmit({ userId: '[email protected]', password: 'password', siteName: 'sample' }); 
    expect(localStorage.setItem).toHaveBeenCalledWith('token', 'newToken'); 
    expect(login._currentUser.set).toHaveBeenCalledWith({ 'test': 'one' }); 
    expect(login.router.navigate).toHaveBeenCalledWith(['/Home']); 
})); 

希望這可以幫助別人的未來。

1

我猜你想要一個模擬Router實例注入到你的組件,然後navigate(['/Home'])後,叫上模擬Router,你是否localStorage.setItem(...)被調用。

+0

感覺就像檢查會發生,他們接到電話,因爲之前的認購,但我是新觀察者。此外,我們以前只是在Angular 1中使用spyOn(localStorage,'setItem'),但我很難搞清楚如何對Angular 2做同樣的處理。 – HomeBrew

+0

我的不好,看起來你仍然使用spyOn相同,我的問題是我無法弄清楚你需要從哪裏導入'spyOn',但似乎你只是擁有它。但是,似乎我之前對支票發生的陳述仍然正確。我已經更新了我的問題以包含規範。 – HomeBrew

-1

See my gist here

基本上你可以在這裏做幾件事。首先,用你想要的令牌(或其他響應)的簡單可觀察的響應來存儲你的http調用(我從服務中猜測出來)。

service.stub.ts

export class MyStub { 
    public create(user: User): Observable<User> { 
    return Observable.of('insert test token here'); 
    } 
// other stubbed methods ... 
} 

然後你的測試裏面:

myComp.spec.ts

let comp: MyComponent; 
let fixture: ComponentFixture<MyComponent>; 
let sst: ServiceStub; 
describe('MyComponent',() => { 
    beforeEach(async(() => { 
    TestBed.configureTestingModule({ 
     declarations: [MyComponent], 
     schemas: [NO_ERRORS_SCHEMA] 
    }).overrideComponent(OnboardFacilityNewComponent, { 
     set: { 
     providers: [ 
      { provide: MyService, useClass: ServiceStub }, 
     ] 
     } 
    }) 
    .compileComponents() 
     .then(() => { 
     fixture = TestBed.createComponent(MyComponent); 
     comp = fixture.componentInstance; 
     st = fixture.debugElement.injector.get(MyService); 
     }); 
    })); 
    it('should submit new onboardFacility', fakeAsync(() => { 
    const sst = spyOn(sst, 'create').and.returnValue(
     Observable.of('some token here') 
    ); 
    comp.onSubmit(testUser); 
    fixture.detectChanges(); 
    expect(comp.token).toEqual('some token here'); 
    expect(spy.calls.any()).toEqual(true); 
    })); 
}); 

在這裏,你可以簡單地替換測試數據與實際數據測試你的測試行爲,而不是你的測試平臺,你的服務,localStorage等等。顯然,我在這裏寫的測試假設你會將你的服務返回的令牌存儲在你的組件中,r ather然後localStorage (though there is a way to do that),但我只是簡單地顯示的概念,而不是你的具體用例。

在您的使用情況下,你還需要存根路由器,你可以學習如何做here.

+0

這是沒有道理的。你爲什麼在服務模擬中調用spyOn?如果它被嘲笑,它也返回一個模擬值,你不需要用returnValue Jasmine函數返回另一個模擬值。 –

+0

@EliasGarcia因爲您正在確定函數邏輯是否調用依賴關係。間諜是可選的。 –