web-dev-qa-db-ja.com

コンポーネントをAngular 4でモックする方法?-単体テスト

Angular 4.のプロバイダーでコンポーネントをモックするのに問題があります。以下にコードを示します。

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/core/platform-browser';
import { DebugElement } from '@angular/core';
import { FormsModule,
    ReactiveFormsModule,
    FormBuilder
} from '@angular/forms';
import { Router, RouterModule } from '@angular/router';
import {
    Http, ConnectionBackend,
    BaseRequestOptions
} from '@angular/http';
import { MockBackend, async } from '@angular/http/testing';

import { LoginComponent } from './../../../src/app/login/login.component';
import { LoginService } from './../../../src/app/login/login.service';
import { LoginComponent } from './../../../src/app/login/login.component';
import { LoggerService } from './../../../src/app/logger-service';
import { AuthService } from './../../../src/app/pages/auth.service';

describe('LoginComponent', () => {
    let comp: LoginComponent;
    let fixture: ComponentFixture<LoginComponent>;
    let de: DebugElement;
    let el: HTMLElement;

    beforeEach(() => {
        // implement mock
        class loggerService = {

        };

        class loginService = {

        };

        class authService = {

        };

        class router = {

        };

        TestBed.configureTestingModule({
            declarations: [ LoginComponent ],
            imports: [
                ReactiveFormsModule,
                FormsModule
            ],
            providers: [
                MockBackend,
                BaseRequestOptions,
                AuthService,
                LoginService,
                LoggerService,
                RouterModule,
                { provide: AuthService, useValue: authService },
                { provide: LoginService, useClass: LoginService },
                { provide: LoggerService, useValue: loggerService },
                {
                    provide: Http, useFactory: (backend: ConnectionBackend,
                        defaultOptions: BaseRequestOptions) => {
                        return new Http(backend, defaultOptions);
                    }, deps: [MockBackend, BaseRequestOptions]
                },
                { provide: Router, useClass: router }
            ]
        }).compileComponents().then(() => {
            fixture = TestBed.createComponent(LoginComponent);

            comp = fixture.componentInstance;

            comp.detectChanges();
            comp.ngOnInit();

            loginService = fixture.debugElement.injector.get(LoginService);
            loggerService = fixture.debugElement.injector.get(LoggerService);
            authService = fixture.debugElement.injector.get(AuthService);
            router = fixture.debugElement.injector.get(Router);
        });

    });

    it('should create component', async(() => {
        expect(comp).toBeDefined();
    }));
});

ここに私のエラーがあります:

spec-bundle.js:9未処理のPromiseの拒否:AuthServiceのプロバイダーがありません! ;ゾーン:ProxyZone;タスク:Promise.then;値:エラー{__zone_symbol__error:Error.ZoneAwareErrorでのエラー( http:// localhost:9876/base/config/spec-bundle.js:9:3748709 )a……}

私が間違っていることについてのアイデアはありますか?

前もって感謝します :)

11
Megan

それで、いくつかのことが飛び出してきました。彼らがあなたの問題かどうかはわかりません。

空のクラスをスタブ化し、それらを使用して実際のサービスの代わりにコンポーネントにモックインジェクトし、それらのインジェクションされたサービスをスタブ変数に割り当てようとしています。代わりに、合法的なサービスを使用するか、それらをスタブしてそれらへの別の参照を取得しようとします。

AuthServiceの場合、実際のサービスを提供したい場合(後でその部分を傍受してスパイしたとしても)、あなたはただ言うことができます

...
providers: [AuthService]
...

モックしたい場合は、次を使用します。

class mockAuthService{}
beforeEach(() => {
    TestBed.configureTestingModule({
    ...
    providers: [{provide: AuthService, useClass: mockAuthService}] 
    ...

または

let mockAuthService;
beforeEach(() => {
    mockAuthService = {}
    TestBed.configureTestingModule({
    ...
    providers: [{provide: AuthService, useValue: mockAuthService}] 
    ...

また、これが問題であることを再確認することはできません。これをすべてbeforeEachスコープ内で実行し、外部ではありませんでした(したがって、必要に応じて後でこれらの変数を参照できます)。上/下に示したように、それをbeforeEach()の上に移動します。

ここに私が言っていることの例があります。

describe('LoginComponent', () => {
    let comp: LoginComponent;
    let fixture: ComponentFixture<LoginComponent>;
    let de: DebugElement;
    let el: HTMLElement;


let authServiceReference;

beforeEach(() => {
    TestBed.configureTestingModule({
        declarations: [ LoginComponent ],
        imports: [
            ReactiveFormsModule,
            FormsModule
        ],
        providers: [
            MockBackend,
            BaseRequestOptions,
            AuthService,
            LoginService,
            LoggerService,
            RouterModule,                
            {
                provide: Http, useFactory: (backend: ConnectionBackend,
                    defaultOptions: BaseRequestOptions) => {
                    return new Http(backend, defaultOptions);
                }, deps: [MockBackend, BaseRequestOptions]
            }, 
            Router

        ]
    }).compileComponents().then(() => {
        fixture = TestBed.createComponent(LoginComponent);

        comp = fixture.componentInstance;

        comp.detectChanges();
        comp.ngOnInit();


        authServiceReference = Testbed.get(AuthService); // get service you injected above

    });

});

it('should create component', () => {
    expect(comp).toBeDefined();
}); // this part really doesn't need to be async. 

いくつかの追加事項(私も比較的新しく、これらは私が取り上げたものです)。テスト自体で、挿入されたサービスへの参照を取得するだけで、混乱が少なくなります。例:

it('should have a service', inject([SomeService], (serviceHandle: SomeService) => {
     expect(serviceHandle).toEqual(sameServiceYouTriedToGrabInInitialSetUp);
}

それが理にかなっていることを願っています。要するに、そこにあるものをつかむほうがずっと簡単です。さらに、that特定のテストのためにハンドルを取得したい数のサービスを注入できます。

 it('should have a service', inject([SomeService, SomeOtherService, YetOneMoreService], (serviceHandle: SomeService, otherServiceHandle: SomeOtherService, yetAnotherHandle: YetOneMoreService) => {
         spyOn(serviceHandle, 'isAuthenticated').and.returnsValue(true);
         spyOn(otherServiceHandle, 'getUrl').and.returnsValue(/home);
         let yahSpy = spyOn(yetAnotherHandle, 'doSomething');
         //code
          expect (yahSpy.doSomething).toHaveBeenCalled();

    }

お役に立てれば。

10
Angelo