2016-10-21 30 views
6

Tôi đang cố gắng thử nghiệm thành phần Angular 2 sử dụng dịch vụ. Các dịch vụ đã Http tiêm vào nó, mà tôi không quan tâm đến thử nghiệm vì vậy tôi đang cố gắng để thử các dịch vụ và gián điệp về cuộc gọi phương thức của dịch vụ. Đây là một cái gì đó tôi đã khá quen thuộc với làm trong Angular 1 nhưng tôi chỉ không thể làm việc trong Angular 2. Lỗi tôi nhận được là Không có nhà cung cấp cho Http! Tôi quan tâm đến việc theo dõi các phương pháp dịch vụ thực tế hơn là chế nhạo nó.Kiểm tra thành phần góc 2 với gián điệp Jasmine "Không có nhà cung cấp cho Http!" lỗi

thành phần của tôi trông như thế này:

import { Component, OnInit } from '@angular/core'; 
import { NavBarLink } from '../../models/nav-bar-link'; 
import { NavBarService } from '../../services/nav-bar/nav-bar.service'; 

@Component({ 
    selector: 'nav-bar', 
    providers: [NavBarService], 
    moduleId: module.id, 
    templateUrl: 'nav-bar.template.html' 
}) 
export class NavBarComponent { 
    constructor(private _navBarService: NavBarService) { } 

links: NavBarLink[]; 

getLinks(): void { 
    this._navBarService.getNavBarLinks().then(data => this.links = data); 
} 

ngOnInit(): void { 
    this.getLinks(); 
    } 
} 

Và dịch vụ của tôi trông như thế này:

import { Injectable } from '@angular/core'; 
import { Headers, Http } from '@angular/http'; 

import 'rxjs/add/operator/toPromise'; 

import { Urls } from '../../constants/urls.constants'; 
import { NavBarLink } from '../../models/nav-bar-link'; 

@Injectable() 
export class NavBarService { 
    constructor(private _http: Http, 
       private _urls: Urls) { } 

    getNavBarLinks():Promise<NavBarLink[]> { 

     return this._http.get(this._urls.NAV_BAR_LINKS)  
      .toPromise() 
      .then(response => { 
       let navLinks = []; 
       for(let navLink of response.json()) { 
        navLinks.push(new NavBarLink(navLink.id,  navLink.description, navLink.route)); 
       } 
       return navLinks; 
      }) 
      .catch(this.handleError); 

    } 

    private handleError(error: any): Promise<any> { 
     console.error('An error occurred', error); // for demo purposes only 
     return Promise.reject(error.message || error); 
    } 

} 

Và cuối cùng thử nghiệm của tôi trông như thế này

import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 
import { Provider } from '@angular/core'; 
import { By }    from '@angular/platform-browser'; 
import { DebugElement } from '@angular/core'; 

import { NavBarComponent } from './nav-bar.component'; 
import { NavBarService } from '../../services/nav-bar/nav-bar.service'; 

import { Observable } from 'rxjs/Rx'; 

let comp: NavBarComponent; 
let fixture: ComponentFixture<NavBarComponent>; 
let navBarService; 

class MockNavBarService extends NavBarService{ 
    constructor() { 
     super(null, null); 
    } 
} 

describe ('NavBarComponent tests',() => { 

    beforeEach(async(() => { 
     TestBed.configureTestingModule({ 
       declarations: [ NavBarComponent ], 
       providers: [ {provide: NavBarService, useClass:  MockNavBarService} ] 
      }) 
      .compileComponents() 
      .then(createComponent); 
    })); 


    it('should call the getNavBarLinks when ngOnInit is called',() => { 
     comp.ngOnInit(); 
     expect(navBarService.getNavBarLinks).toHaveBeenCalled(); 
    }); 
}); 

function createComponent() { 
    fixture = TestBed.createComponent(NavBarComponent); 
    comp = fixture.componentInstance; 

    navBarService = fixture.debugElement.injector.get(NavBarService); 

    spyOn(navBarService, 'getNavBarLinks').and.returnValue(Promise.resolve([])); 
} 

Trả lời

0

Đó là vì điều này

@Component({ 
    providers: [NavBarService], <==== !!!!! 
}) 
export class NavBarComponent { 

@Component.providers có quyền ưu tiên hơn bất kỳ thứ gì được cung cấp và cấp mô-đun. Vì vậy, Angular sẽ cố gắng tạo ra thể hiện của NavBarService thay vì sử dụng mô hình bạn đã cấu hình trong thử nghiệm.

Góc cho phép chúng tôi ghi đè số @Component.providers cũng như các thứ khác như @Component.template. Chúng tôi có thể thực hiện điều đó với một trong các trường hợp sau đây

TestBed.configureTestingModule({ 
    declarations: [NavBarComponent] 
}) 
.overrideComponent(NavBarComponent, { 
    set: { 
    providers: [ 
     { provide: NavBarService, useClass: MockNavBarService} 
    ] 
    } 
}) 
.compileComponents() 
.then(createComponent) 
0

Vấn đề là MockNavBarService mở rộng NavBarService, vì vậy, Http vẫn sẽ được cung cấp. Tôi không hiểu lý do kỹ thuật tại sao đây là trường hợp, nhưng có nó. Nếu bạn loại bỏ các thừa kế, bạn thay vào đó có thể thực hiện một mô hình getNavBarLinks() trả về một quan sát của một số dữ liệu đóng hộp. Sau đó, trong thử nghiệm của bạn, bạn có thể kiểm tra những gì NavBarComponent làm với dữ liệu chứ không phải là kiểm tra thực tế là một số phương pháp đã được gọi.

6

Cảm ơn sự giúp đỡ của mọi người, nó giúp tôi tìm kiếm đúng khu vực. Những gì còn thiếu là nhập khẩu HttpModule. Cảm ơn Ahmed vì đã đề xuất điều này. Dưới đây là bài kiểm tra cố định của tôi để tham khảo:

import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 
import { Provider } from '@angular/core'; 
import { By }    from '@angular/platform-browser'; 
import { DebugElement } from '@angular/core'; 
import { HttpModule } from '@angular/http'; // <==== IMPORT THIS 

import { MockBackend } from '@angular/http/testing'; 
import { NavBarComponent } from './nav-bar.component'; 
import { NavBarService } from '../../services/nav-bar/nav-bar.service'; 
import { Urls } from '../../constants/urls.constants'; 

import { Observable } from 'rxjs/Rx'; 

let comp: NavBarComponent; 
let fixture: ComponentFixture<NavBarComponent>; 
var navBarService; 

describe ('NavBarComponent tests',() => { 

    beforeEach(async(() => { 
     TestBed.configureTestingModule({ 
       declarations: [ NavBarComponent ], 
       imports: [ HttpModule], //<==IMPORT INTO TEST BED 
       providers: [ 
        Urls, 
        MockBackend, 
        NavBarService ] 
      }) 
      .compileComponents() 
      .then(createComponent); 
    })); 


    it('should call the getNavBarLinks when ngOnInit is called',() => { 
     comp.ngOnInit(); 
     expect(navBarService.getNavBarLinks).toHaveBeenCalled(); 
    }); 
}); 

function createComponent() { 
    fixture = TestBed.createComponent(NavBarComponent); 
    comp = fixture.componentInstance; 

    navBarService = fixture.debugElement.injector.get(NavBarService); 

    spyOn(navBarService,  'getNavBarLinks').and.returnValue(Promise.resolve([])); 
} 

Không cần cho các đối tượng giả hoặc bất cứ điều gì, hoàn hảo

+2

Vấn đề với giải pháp này là bạn đang mang trong module mà phụ thuộc của dịch vụ mà thành phần của bạn tiêu thụ mà tăng thêm độ phức tạp cho thử nghiệm thành phần của bạn. Bất kỳ lúc nào NavBarService thay đổi các nhà cung cấp của nó, bạn phải cập nhật mọi tệp kiểm tra tiêu thụ hoặc dựa vào NavBarComponent. Bằng cách chế nhạo dịch vụ với một lớp không mở rộng dịch vụ ban đầu, bạn cắt sự phức tạp phụ thuộc đó ra khỏi thư mục gốc của nó. Điều này sẽ làm cho các bài kiểm tra của bạn sạch hơn và ít dễ bị chú ý hơn nếu bạn thay đổi dịch vụ. – pe8ter

Các vấn đề liên quan