web-dev-qa-db-fra.com

Comment se moquer des composants avec les fournisseurs dans Angular 4? - Test unitaire

J'ai un problème pour me moquer d'un composant avec des fournisseurs dans Angular 4. Voici le code:

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();
    }));
});

Voici mon erreur:

spec-bundle.js: 9 Rejet de promesse non géré: Aucun fournisseur pour AuthService! ; Zone: ProxyZone; Tâche: Promise.then; Valeur: erreur {__zone_symbol__error: erreur à Error.ZoneAwareError ( http: // localhost: 9876/base/config/spec-bundle.js: 9: 3748709 ) a ……}

Une idée de ce que je fais mal?

Merci d'avance :)

11
Megan

Donc, deux choses me sautent aux yeux. Je ne sais pas si c'est votre problème.

Vous essayez d'extraire des classes vides, de les utiliser pour simuler l'injection dans votre composant à la place d'un service réel, puis de réaffecter ces services injectés aux variables de stub. Au lieu de cela, j'essaierais soit d'utiliser les services légitimes, soit de les supprimer et d'obtenir une référence distincte pour eux.

Dans le cas d'AuthService, si vous voulez fournir le vrai service (même si plus tard vous interceptez et espionnez ses pièces), vous pouvez simplement dire

...
providers: [AuthService]
...

Si vous voulez vous en moquer, vous utiliseriez:

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

ou

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

De plus, et je ne peux pas vérifier pour vérifier qu'il s'agit d'un problème, vous faisiez tout cela à l'intérieur de la portée beforeEach, pas à l'extérieur (vous pouvez donc vous référer ultérieurement à cette variable, en supposant que vous le vouliez). Je déplacerais cela au-dessus de votre beforeEach (), comme je l'ai montré ci-dessus/ci-dessous.

Voici un exemple de ce que je veux dire.

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. 

Quelques choses supplémentaires (je suis relativement nouveau aussi, et ce sont des choses que j'ai ramassées). Vous trouverez peut-être moins encombrant de simplement saisir une référence aux services injectés lors du test lui-même. Exemple:

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

J'espère que cela a du sens lol. Le point étant, il est beaucoup plus facile de simplement l'attraper là. De plus, vous pouvez injecter autant de services que vous le souhaitez pour gérer un test particulier 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();

    }

J'espère que cela t'aides.

10
Angelo