2017-03-14 3 views
0

これは、を持つComponentのテスト例で、angular2のドキュメントで提供されているスタブを使用しています。TestBedを使用したサービススタブへの変更の検出

私がそれをビルドして実行しようとしているとき、コンポーネントが2番目のテストケースの変更を受け取っていないことがわかります。私はいつもメッセージを見る。

サービスはこのようになります。「角度/コア@」から

インポート{注射}。

@Injectable() 
export class UserService { 
    isLoggedIn: true; 
    user: { name: string }; 
} 

コンポーネントは次のようになります。

import { Component, OnInit } from '@angular/core'; 
import { UserService } from './user.service'; 

@Component({ 
    moduleId: module.id, 
    selector: 'app-welcome', 
    templateUrl: './welcome.component.html' 
}) 
export class WelcomeComponent implements OnInit { 
    welcome = '--- not initialized yet'; 

    constructor (private userService: UserService) {} 

    ngOnInit() { 
    this.welcome = this.userService.isLoggedIn ? 
     'Welcome, ' + this.userService.user.name : 
     'Please log in.'; 
    } 
} 

これは、問題のユニットテストです:

import { async, TestBed, ComponentFixture, ComponentFixtureAutoDetect } from '@angular/core/testing'; 
import { DebugElement } from '@angular/core'; 
import { By } from '@angular/platform-browser'; 
import { UserService } from './user.service'; 
import { WelcomeComponent } from './welcome.component'; 


let fixture: ComponentFixture<WelcomeComponent>; 
let comp: WelcomeComponent; 
let de: DebugElement; 
let el: HTMLElement; 
let userService: UserService; 

describe('Welcome Component (testing a component with a service)',() => { 
    beforeEach(async(() => { 
    const userServiceStub = { 
     isLoggedIn: true, 
     user: { 
     name: 'Test User' 
     } 
    }; 
    return TestBed.configureTestingModule({ 
     declarations: [ 
     WelcomeComponent 
     ], 
     providers: [ 
     { 
      provide: ComponentFixtureAutoDetect, 
      useValue: true 
     }, 
     { 
      provide: UserService, 
      useValue: userServiceStub 
     } 
     ] 
    }).compileComponents(); // DO NOT USE WITH WEBPACK 
    })); 

    beforeEach(() => { 
    fixture = TestBed.createComponent(WelcomeComponent); 
    userService = TestBed.get(UserService); 
    comp = fixture.componentInstance; 
    de = fixture.debugElement.query(By.css('.welcome')); 
    el = de.nativeElement; 
    }); 

    it('should welcome the user',() => { 
    fixture.detectChanges(); 
    const content = el.textContent; 
    expect(content).toContain('Welcome', '"Welcome..."'); 
    }); 

    it('should welcome Bubba',() => { 
    userService.user.name = 'Bubba'; 
    fixture.detectChanges(); 
    expect(el.textContent).toContain('Bubba'); 
    }); 

}); 

エラーが常にある:

Expected 'Welcome, Test User' to contain 'Bubba'. 

エラー: 'Welcome、Test User'には 'Bubba'が含まれています。

デバッグ時に、サービススタブが適切な値で更新されていることがわかりました。

+0

あなたはテンプレートに直接サービスにアクセスしていますか? –

+0

@peeskillet私はスタブを使用して、 'TestBed.get(UserService);'を使って 'beforeEach'でそれを取得しようとしています。それはスタブを取り、それをサービスに変えますが、値を変更することはできません。私はサービスにアクセスする 'ngOnInit'にプロパティを作成しています。 – vamsiampolu

+0

ええ、テンプレート内のサービスに直接アクセスしている場合を除き、サービスの値を変更するとテンプレートに影響するはずです。サービスの値に基づいてコンポーネント内の変数を割り当てる場合、これは初期の初期化に過ぎず、サービス更新時のコンポーネント変数は更新されません。代わりにSubjectをサービスに使用して、コンポーネントの値をサブスクライブすることができます。 –

答えて

1

あなたがここに

をやって何
welcome = '--- not initialized yet'; 

ngOnInit() { 
    this.welcome = this.userService.isLoggedIn ? 
    'Welcome, ' + this.userService.user.name : 
    'Please log in.'; 
} 

一度だけ初期化です。その後のサービスの更新では、再初期化は行われません。

代わりに、サブスクリプションシステムを使用して、更新プログラムを購読することができます。たぶん

welcome = '--- not initialized yet'; 

ngOnInit() { 
    this.userService.status$.subscribe(status) => { 
    let loggedIn = status.isLoggedIn; 
    let user = status.user; 
    this.welcome = '...' 
    }) 
} 

のようなものあなたは、あなたが新しい値を発することができるBehaviorSubjectSubjectまたは多分より良いを使用するようにサービスを変更する必要があります。これらの新しい排出量はコンポーネントSubject

class UserService { 
    private _isLoggedIn: boolean = false; 
    private _user = { name: 'Anonymous' }; 

    private _status = new BehaviorSubject({ 
    isLoggedIn: this._isLoggedIn 
    user: this._user 
    }); 

    get status$() { 
    return this._status.asObservable(); 
    } 

    updateUserName(name: string) { 
    this._user.name = name; 
    this.emit(); 
    } 

    updateIsLoggedIn(loggedIn: boolean) { 
    this.isLoggedIn = loggedIn; 
    if (!loggedIn) { 
     this._user.name = 'Anonymous; 
    } 
    this.emit(); 
    } 

    private emit() { 
    this._status.next({ 
     isLoggedIn: this._isLoggedIn, 
     user: this._user 
    }) 
    } 
} 

によってサブスクライブされるだろう、あなたはnext(..)を呼び出して、新しい値を放出し、これまでに何がそれに渡すことができ、加入者に放出されます。

今テストでは、サービスupdateUserNameを呼び出すことができます。あなたは、テストのためのサービスをスタブしたい場合は、

let mockService = { 
    status$: new Subject<>(); 
} 

mockService.status$.next(...) 

ような何かを行うことができます。しかし、本当に、そのままサービスで、任意の外部の依存関係を使用していない、それを模擬する必要は本当にありません。

サービスが非同期であるため、テストにはasyncまたはfakeAsyncを使用する必要があります。

import { fakeAsync, async, tick + from '@angular/core/testing'; 

it('..', fakeAsync(() => { 
    service.updateUserName(..) 
    tick(); 
    expect(...) 
})) 

it('..', async(() => { 
    service.updateUserName(..) 
    fixture.whenStable().then(() => { 
    expect(...) 
    }) 
})) 
関連する問題