2016-03-01 16 views
16

Seguendo l'esempio di codice trovato su Ari Lerner ng-book2 e utilizzando Angular 2 beta 7, sto cercando di deridere e spiare una chiamata a un servizio senza successo.Come spiare una chiamata di servizio in Angular2

Questo è il componente principale utilizzando il servizio:

user-list.component.ts

import {Component, OnInit} from 'angular2/core'; 
import {UserService} from './user.service'; 
import {IUser} from './user.model'; 

@Component({ 
    selector: 'user-list', 
    providers: [UserService], 
    template: ` 
    <div *ngFor="#user of users" class="user"> 
     <span class="username">Username: {{ user.username }}</span><br> 
     <span class="email">Email: {{ user.email }}</span> 
    </div> 
    ` 
}) 
export class UserListComponent implements OnInit { 
    public users: IUser[]; 
    private userService: UserService; 

    constructor(userService: UserService) { 
    this.userService = userService; 
    } 

    ngOnInit(): void { 
    this.userService.getAllUsers().subscribe(
     (users: IUser[]) => { 
     this.users = users; 
     }, 
     (error: any) => { 
     console.log(error); 
     } 
    ); 
    } 
} 

E questo è il servizio stesso.

user.service.ts

import {Injectable} from 'angular2/core'; 
import {Http} from 'angular2/http'; 
import {Observable} from 'rxjs/Observable'; 
import 'rxjs/Rx'; 
import {IUser} from './user.model'; 

@Injectable() 
export class UserService { 
    private http: Http; 
    private baseUrl: string = 'http://jsonplaceholder.typicode.com/users'; 

    constructor(http: Http) { 
    this.http = http; 
    } 

    public getAllUsers(): Observable<IUser[]> { 
    return this.http.get(this.baseUrl) 
     .map(res => res.json()); 
    } 
} 

Al fine di testare la UserListComponent, sto cercando di prendere in giro il UserService e spiare la sua chiamata di metodo getAllUser utilizzando il seguente codice:

utente -list.component.spec.ts

import { 
    describe, 
    expect, 
    it, 
    injectAsync, 
    TestComponentBuilder, 
    ComponentFixture, 
    setBaseTestProviders, 
} from 'angular2/testing'; 

import {SpyObject} from 'angular2/testing_internal'; 

import { 
    TEST_BROWSER_PLATFORM_PROVIDERS, 
    TEST_BROWSER_APPLICATION_PROVIDERS 
} from 'angular2/platform/testing/browser'; 

import {provide} from 'angular2/core'; 

import {UserListComponent} from './user-list.component'; 
import {UserService} from './user.service'; 

class SpyUserService extends SpyObject { 
    public getAllUsers: Function; 
    public fakeResponse: any = null; 

    constructor() { 
    super(UserService); 
    this.getAllUsers = this.spy('getAllUsers').andReturn(this); 
    } 

    public subscribe(callback) { 
    callback(this.fakeResponse); 
    } 

    public setResponse(data: any): void { 
    this.fakeResponse = data; 
    } 
} 

describe('When rendering the UserListComponent and mocking the UserService',() => { 

    setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS, TEST_BROWSER_APPLICATION_PROVIDERS); 

    it('should show one mocked user', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => { 

    let spyUserService = new SpyUserService(); 
    spyUserService.setResponse([{ 
     username: 'ryan', 
     email: '[email protected]' 
    }]); 

    return tcb 
     .overrideProviders(UserListComponent, [provide(UserService, {useValue: spyUserService})]) 
     .createAsync(UserListComponent) 
     .then((fixture: ComponentFixture) => { 
     fixture.detectChanges(); 
     expect(spyUserService.getAllUsers).toHaveBeenCalled(); 
     }); 
    })); 

}); 

Quando si utilizza il karma per eseguire il test sto ottenendo il seguente errore console:

Chrome 48.0.2564 (Mac OS X 10.11.3) ERROR 
    Uncaught TypeError: Cannot read property 'isSlow' of null 
    at /Users/david/apps/sandbox/angular2-testing-cookbook/src/tests.entry.ts:19430 

Do Qualcuno sa il motivo per cui viene questo errore viene gettato o il modo corretto di prendere in giro e spiare un servizio per unità di test di un angolare 2 componente?

+0

Sapete da dove proviene 'isSlow', il codice nella domanda non lo contiene. –

+0

Proviene dal file 'testing_internal' –

risposta

20

prendo un approccio leggermente diverso e utilizzare iniettare si procurarsi l'istanza di servizio attraverso DI invece. Quindi il test sarà simile:

import { 
    describe, 
    expect, 
    it, 
    tick, 
    inject, 
    fakeAsync, 
    TestComponentBuilder, 
    ComponentFixture, 
    addProviders 
} from 'angular2/testing'; 

import { Component, provide } from '@angular/core'; 

import {UserListComponent} from './user-list.component'; 

import {UserService} from './user.service'; 
import {MockUserService} from './user.service.mock'; 

describe('When loading the UserListComponent',() => { 

    beforeEach(() => addProviders([ 
     {provide: UserService, useClass: MockUserService} 
    ])); 

    it('should call the getAllUsers method from the UserService', 
    inject([TestComponentBuilder, UserService], fakeAsync((tcb: TestComponentBuilder, mockUserService: UserService) => { 
     spyOn(mockUserService, 'getAllUsers'); 

     tcb 
     .createAsync(UserListComponent) 
     .then((fixture: ComponentFixture) => { 
      tick(); 
      fixture.detectChanges(); 
      expect(mockUserService.getAllUsers).toHaveBeenCalled(); 
     }); 
    })) 
); 

    it('should show one mocked user', 
    inject([TestComponentBuilder, UserService], fakeAsync((tcb: TestComponentBuilder, mockUserService: UserService) => { 
     mockUserService.setResponse([{ 
     username: 'ryan', 
     email: '[email protected]' 
     }]); 

     tcb 
     .createAsync(UserListComponent) 
     .then((fixture: ComponentFixture) => { 
      tick(); 
      fixture.detectChanges(); 
      let compiled = fixture.debugElement.nativeElement; 
      expect(compiled.querySelector('div:nth-child(1) .username')).toHaveText('Username: ryan'); 
      expect(compiled.querySelector('div:nth-child(1) .email')).toHaveText('Email: [email protected]'); 
     }); 
    })) 
); 

}); 

Modifica per angolare 4

L'ultima docs hanno un modo più semplice di entrare in possesso di un servizio utilizzando l'iniettore del componente:

fixture = TestBed.createComponent(TestComponent); 
    component = fixture.componentInstance; 
    const mockService = fixture.debugElement.injector.get(MyService); 
+0

Questo è un approccio migliore, grazie –

+0

È questo Angular2? Posso chiederti da come ottieni questa funzione 'spyOn'? Sto usando '" @ angular/core ":" 2.0.0-rc.3 ",' e non so da dove posso importarlo per usarlo. Qualcuno può suggerire una risorsa/esempio/documentazione? –

+1

@ RogérioRodriguesdeAlcântara spyOn è parte di [Jasmine] (http://jasmine.github.io/2.0/introduction.html). C'è un progetto di esempio [qui] (https://github.com/juliemr/ng2-test-seed) che ho trovato utile da usare come guida e ha anche [questo] (https://www.youtube. com/watch? v = C0F2E-PRm44 & feature = youtu.be & list = PLTqvbBh8rJwhFiIiqRrIE3FzyD_CXtHAf) tutorial da seguire. – JayChase

4

ho trovato la soluzione

test.entry.ts

import {setBaseTestProviders} from 'angular2/testing'; 

import { 
    TEST_BROWSER_PLATFORM_PROVIDERS, 
    TEST_BROWSER_APPLICATION_PROVIDERS 
} from 'angular2/platform/testing/browser'; 

setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS, TEST_BROWSER_APPLICATION_PROVIDERS); 

import './user-list.component.spec'; 

user-list.component.spec.ts

import { 
    describe, 
    expect, 
    it, 
    tick, 
    inject, 
    fakeAsync, 
    TestComponentBuilder, 
    ComponentFixture, 
    beforeEachProviders 
} from 'angular2/testing'; 

import {UserListComponent} from './user-list.component'; 
import {MockUserService} from './user.service.mock'; 

describe('When loading the UserListComponent',() => { 

    let mockUserService: MockUserService; 

    beforeEachProviders(() => { 
    mockUserService = new MockUserService(); 
    return [mockUserService.getProvider()]; 
    }); 

    it('should call the getAllUsers method from the UserService', 
    inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => { 
     spyOn(mockUserService, 'getAllUsers'); 

     tcb 
     .createAsync(UserListComponent) 
     .then((fixture: ComponentFixture) => { 
      tick(); 
      fixture.detectChanges(); 
      expect(mockUserService.getAllUsers).toHaveBeenCalled(); 
     }); 
    })) 
); 

    it('should show one mocked user', 
    inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => { 
     mockUserService.setResponse([{ 
     username: 'ryan', 
     email: '[email protected]' 
     }]); 

     tcb 
     .createAsync(UserListComponent) 
     .then((fixture: ComponentFixture) => { 
      tick(); 
      fixture.detectChanges(); 
      let compiled = fixture.debugElement.nativeElement; 
      expect(compiled.querySelector('div:nth-child(1) .username')).toHaveText('Username: ryan'); 
      expect(compiled.querySelector('div:nth-child(1) .email')).toHaveText('Email: [email protected]'); 
     }); 
    })) 
); 

}); 

utente. service.mock.ts

import {provide, Provider} from 'angular2/core'; 
import {UserService} from './user.service'; 
import * as Rx from 'rxjs/Rx'; 

export class MockUserService { 

    public fakeResponse: any = null; 

    public getAllUsers(): Rx.Observable<any> { 
    let subject = new Rx.ReplaySubject() 
    subject.next(this.fakeResponse); 
    return subject; 
    } 

    public setResponse(response: any): void { 
    this.fakeResponse = response; 
    } 

    public getProvider(): Provider { 
    return provide(UserService, {useValue: this}); 
    } 
} 
4

Per tutti i neofiti da provare in angular 2 (come me)

I metodi createSpy o SpyOn sono solo 'disponibili' se hai le tipizzazioni corrette per il gelsomino installato. Altrimenti ti verrà generato un errore di dattiloscritto.

controllo nel file typings.json e se non è presente, eseguire questo

tipizzazioni installare --save registro --global: dt/gelsomino

3

Le altre soluzioni non ha funzionato per me, così ho iniettato il servizio con injector da debugElement.

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

@injectable() 
class MyService { 
    public method() {} 
} 

let MyMockedService = { 
    method:() => {} 
} 

@Component({ 
    template: '' 
}) 
class MyComponent { 
    constructor(private myService: MyService) {;} 
    public method() { 
    this.myService.method(); 
    } 
} 

describe('Test',() => { 
    beforeEach(async(() => { 
    TestBed 
     .configureTestingModule({ 
     imports: [ 
      CommonModule 
     ], 
     declarations: [ 
      MyComponent 
     ], 
      providers: [ 
      { provide: MyService, useValue: MyMockedService} 
     ] 
     }) 
     .compileComponents() 
     .then(() => { 
     fixture = TestBed.createComponent(MyComponent); 
     myComponent = fixture.componentInstance; 
     }); 
    })); 
    it('should spy on service',() => { 
    let myMockedService = fixture.debugElement.injector.get(MyMockedService); 
    spyOn(myMockedService, 'method'); 
    myComponent.method(); 
    expect(myMockedService.method); 
    }); 
}) 
Problemi correlati