2017-07-15 66 views
2

我一直在試圖單元測試一個服務(AuthService),取決於AngularFireAuth單元測試使用AngularFireAuth和模擬的服務authState

我正試圖找到一種方法來模擬或撬開Observable AngularFireAuth.authState,而不是實際與Firebase交談的服務。

這裏是我的測試規範:

import { inject, TestBed } from '@angular/core/testing'; 

import { AngularFireModule } from 'angularfire2'; 
import { AngularFireAuth, AngularFireAuthModule } from 'angularfire2/auth'; 
import * as firebase from 'firebase/app'; 
import 'rxjs/add/observable/of'; 
// import { BehaviorSubject } from 'rxjs/BehaviorSubject'; 
import { Observable } from 'rxjs/Rx'; 

import { AuthService } from './auth.service'; 
import { environment } from '../../environments/environment'; 

const authState: firebase.User = null; 
const mockAngularFireAuth: any = { authState: Observable.of(authState) }; 

describe('AuthService',() => { 
    beforeEach(() => { 
    TestBed.configureTestingModule({ 
     imports: [AngularFireModule.initializeApp(environment.firebaseAppConfig)], 
     providers: [ 
     { provider: AngularFireAuth, useValue: mockAngularFireAuth }, 
     AuthService 
     ] 
    }); 
    }); 

    it('should be defined', inject([ AuthService ], (service: AuthService) => { 
    expect(service).toBeDefined(); 
    })); 

    it('.authState should be null', inject([ AuthService ], (service: AuthService) => { 
    expect(service.authState).toBe(null); 
    })); 
}); 

這裏是我(簡化)服務:

import { Injectable } from '@angular/core'; 

import { AngularFireAuth } from 'angularfire2/auth'; 
import * as firebase from 'firebase/app'; 
import { Observable } from 'rxjs/Rx'; 

@Injectable() 
export class AuthService { 
    private authState: firebase.User; 

    constructor(private afAuth: AngularFireAuth) { this.init(); } 

    private init(): void { 
    this.afAuth.authState.subscribe((authState) => { 
     if (authState === null) { 
     this.afAuth.auth.signInAnonymously() 
      .then((authState) => { 
      this.authState = authState; 
      }) 
      .catch((error) => { 
      throw new Error(error.message); 
      }); 
     } else { 
     this.authState = authState; 
     } 
    }, (error) => { 
     throw new Error(error.message); 
    }); 
    } 

    public get currentUser(): firebase.User { 
    return this.authState ? this.authState : undefined; 
    } 

    public get currentUserObservable(): Observable<firebase.User> { 
    return this.afAuth.authState; 
    } 

    public get currentUid(): string { 
    return this.authState ? this.authState.uid : undefined; 
    } 

    public get isAnonymous(): boolean { 
    return this.authState ? this.authState.isAnonymous : false; 
    } 

    public get isAuthenticated(): boolean { 
    return !!this.authState; 
    } 

    public logout(): void { 
    this.afAuth.auth.signOut(); 
    } 
} 

我得到的錯誤Property 'authState' is private and only accessible within class 'AuthService'.

當然是,但我不我不想實際訪問它 - 我想模擬或劫持它,所以我可以從我的測試規範中控制它的價值。我相信我的代碼在這裏偏離我的代碼。

請注意我正在使用AngularFire2的版本^4,並且引入了重大更改;這裏記錄:https://github.com/angular/angularfire2/blob/master/docs/version-4-upgrade.md

回答

2

封裝的成員可以被反映。

難的方法:

expect(Reflect.get(service, 'authState')).toBe(null); 

最簡單的辦法:

expect(service['authState']).toBe(null); 
expect((service as any).authState).toBe(null); 
+0

謝謝。那我怎麼能設置'authState'呢?假設我想測試Service中的currentUid getter。歡呼聲 –

+1

不客氣。同樣,使用'Reflect.set(...)'。甚至更簡單,'service ['authState'] = ...'或'(service as any).authState = ...'。它看起來像純粹的TS問題,我會建議將'typescript'標記添加到問題而不是'firebase',因爲它在這裏是相關的。 – estus

+0

太棒了!只是爲了教育自己;即使我不再用模擬重寫'AngularFireAuth'(即不再執行'{provider:AngularFireAuth,useValue:mockAngularFireAuth}'),那麼怎麼沒有調用Firebase?服務中的'init'應該創建一個匿名用戶。這不是(在測試過程中 - 它運行應用程序時),這很好,但爲什麼不呢? –