簡體   English   中英

Angular 2錯誤:在Karma-Jasmine測試中沒有Http的提供者

[英]Angular 2 Error: No provider for Http in Karma-Jasmine Test

即使我的應用程序完美運行且沒有錯誤,我仍然在我的業力測試中收到以下錯誤。 據說沒有Http的提供者。 我正在使用import { HttpModule } from '@angular/http'; 在我的app.module.ts文件中,並將其添加到imports數組中。 業力錯誤如下所示:

Chrome 52.0.2743 (Mac OS X 10.12.0) App: TrackBudget should create the app FAILED
    Failed: Error in ./AppComponent class AppComponent_Host - inline template:0:0 caused by: No provider for Http!
    Error: No provider for Http!
        at NoProviderError.Error (native)
        at NoProviderError.BaseError [as constructor] (webpack:/Users/ChrisGaona%201/budget-tracking/~/@angular/core/src/facade/errors.js:24:0 <- src/test.ts:2559:34)
        at NoProviderError.AbstractProviderError [as constructor] (webpack:/Users/ChrisGaona%201/budget-tracking/~/@angular/core/src/di/reflective_errors.js:42:0 <- src/test.ts:15415:16)
        at new NoProviderError (webpack:/Users/ChrisGaona%201/budget-tracking/~/@angular/core/src/di/reflective_errors.js:73:0 <- src/test.ts:15446:16)
        at ReflectiveInjector_._throwOrNull (webpack:/Users/ChrisGaona%201/budget-tracking/~/@angular/core/src/di/reflective_injector.js:761:0 <- src/test.ts:26066:19)
        at ReflectiveInjector_._getByKeyDefault (webpack:/Users/ChrisGaona%201/budget-tracking/~/@angular/core/src/di/reflective_injector.js:789:0 <- src/test.ts:26094:25)
        at ReflectiveInjector_._getByKey (webpack:/Users/ChrisGaona%201/budget-tracking/~/@angular/core/src/di/reflective_injector.js:752:0 <- src/test.ts:26057:25)
        at ReflectiveInjector_.get (webpack:/Users/ChrisGaona%201/budget-tracking/~/@angular/core/src/di/reflective_injector.js:561:0 <- src/test.ts:25866:21)
        at TestBed.get (webpack:/Users/ChrisGaona%201/budget-tracking/~/@angular/core/bundles/core-testing.umd.js:1115:0 <- src/test.ts:5626:67)
Chrome 52.0.2743 (Mac OS X 10.12.0): Executed 1 of 1 (1 FAILED) ERROR (0.229 secs / 0.174 secs)

這是我的app.component.ts文件:

import {Component} from '@angular/core';
import {Budget} from "./budget";
import {BudgetService} from "./budget.service";

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
    providers: [BudgetService]
})
export class AppComponent {
    title = 'Budget Tracker';

    budgets: Budget[];
    selectedBudget: Budget;

    constructor(private budgetService: BudgetService) { }

    ngOnInit(): void {
        this.budgetService.getBudgets()
            .subscribe(data => {
                this.budgets = data;
                console.log(data);
                this.selectedBudget = data[0];
                console.log(data[0]);
            });
    }
}

這是我的簡單規范:

import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';

describe('App: TrackBudget', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
        declarations: [
            AppComponent
        ]
    });
  });

  it('should create the app', async(() => {
    let fixture = TestBed.createComponent(AppComponent);
    let app = fixture.debugElement.componentInstance;
    expect(app).toBeTruthy();
  }));
});

該錯誤似乎是由我的服務引起的,可以在這里看到:

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import {Budget} from "./budget";

@Injectable()
export class BudgetService {

  constructor(public http: Http) { }

  getBudgets() {
    return this.http.get('budget.json')
        .map(response => <Budget[]>response.json().budgetData);

  }
}

如果我從服務中刪除constructor(public http: Http) { }語句,測試傳遞正常,但隨后應用程序在瀏覽器中失敗。 我已就此做了大量研究,但未能找到解決方案。 任何幫助將不勝感激!!

TestBed的目的是從頭開始為測試環境配置@NgModule 因此,目前您配置的所有內容都是AppComponent沒有其他內容(除了已經在@Component.providers聲明的服務之外)。

我強烈建議你這樣做,而不是試圖像在真實環境中那樣配置所有內容,只是模擬BudgetService 嘗試配置Http並模擬它並不是最好的主意,因為您希望在單元測試時盡可能保持外部依賴性盡可能輕。

這是你需要做的

  1. BudgetService創建一個模擬。 我會查看這篇文章 你可以擴展那個抽象類,添加你的getBudgets方法

  2. 你需要重寫@Component.providers ,在提到這個崗位

如果你真的想要使用真實服務和Http ,那么你需要准備在MockBackend上模擬連接。 您無法使用真正的后端,因為它依賴於平台瀏覽器。 舉個例子,看看這篇文章 在測試組件時,我個人認為這不是一個好主意。 在測試您的服務時,您應該這樣做。

警告 :此解決方案僅在您要測試靜態結構時才有效。 如果您的測試實際上進行了服務調用(並且您最好還有一些測試),它將無法工作。

您的測試使用自己的模塊定義,測試模塊,而不是您的AppModule。 所以你必須在那里導入HttpModule:

TestBed.configureTestingModule({
    imports: [
        HttpModule
    ],
    declarations: [
        AppComponent
    ]
});

您還可以導入AppModule:

TestBed.configureTestingModule({
    imports: [
        AppModule
    ]
});

這樣做的好處是您不必在許多地方添加新組件和模塊。 它更方便。 另一方面,這不太靈活。 您可能在測試中導入的數量超出了您的預期。

此外,您具有從低級組件到整個AppModule的依賴關系。 事實上,這是一種循環依賴,通常是一個壞主意。 所以在我看來,你應該只為那些對你的應用程序至關重要的高級組件這樣做。 對於可能可重用的更多低級組件,最好在測試規范中明確列出所有依賴項。

關於Angular 4+

RC2C的答案對我有用 :)謝謝!

警告 :只有在您沒有真正打電話給您的服務時才會有效。 僅當您要測試靜態結構時,它才有效。

只想添加Angular版本4(可能更高版本),你應該將HttpClientModule導入你的測試床,這樣它看起來像這樣:

import { HttpClientModule } from '@angular/common/http';


describe('BuildingService', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientModule],
      providers: [BuildingService]
    });
  });

  it('should be created 2', inject([BuildingService], (service: BuildingService) => {
    expect(service).toBeTruthy();
  }));

}

小心 :請參閱頂部注意

在app.module.ts中導入HttpModule,它將解決您的問題。

import { HttpModule } from '@angular/http';

@NgModule({
    imports: [HttpModule]
})
...

peeskillet的回答所述, 模擬服務的另一種方法是使用由角度提供模擬后端

API文檔包含以下示例:

import {Injectable, ReflectiveInjector} from '@angular/core';
import {async, fakeAsync, tick} from '@angular/core/testing';
import {BaseRequestOptions, ConnectionBackend, Http, RequestOptions} from '@angular/http';
import {Response, ResponseOptions} from '@angular/http';
import {MockBackend, MockConnection} from '@angular/http/testing';

const HERO_ONE = 'HeroNrOne';
const HERO_TWO = 'WillBeAlwaysTheSecond';

@Injectable()
class HeroService {
  constructor(private http: Http) {}

  getHeroes(): Promise<String[]> {
    return this.http.get('myservices.de/api/heroes')
        .toPromise()
        .then(response => response.json().data)
        .catch(e => this.handleError(e));
  }

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

describe('MockBackend HeroService Example', () => {
  beforeEach(() => {
    this.injector = ReflectiveInjector.resolveAndCreate([
      {provide: ConnectionBackend, useClass: MockBackend},
      {provide: RequestOptions, useClass: BaseRequestOptions},
      Http,
      HeroService,
    ]);
    this.heroService = this.injector.get(HeroService);
    this.backend = this.injector.get(ConnectionBackend) as MockBackend;
    this.backend.connections.subscribe((connection: any) => this.lastConnection = connection);
  });

  it('getHeroes() should query current service url', () => {
    this.heroService.getHeroes();
    expect(this.lastConnection).toBeDefined('no http service connection at all?');
    expect(this.lastConnection.request.url).toMatch(/api\/heroes$/, 'url invalid');
  });

  it('getHeroes() should return some heroes', fakeAsync(() => {
       let result: String[];
       this.heroService.getHeroes().then((heroes: String[]) => result = heroes);
       this.lastConnection.mockRespond(new Response(new ResponseOptions({
         body: JSON.stringify({data: [HERO_ONE, HERO_TWO]}),
       })));
       tick();
       expect(result.length).toEqual(2, 'should contain given amount of heroes');
       expect(result[0]).toEqual(HERO_ONE, ' HERO_ONE should be the first hero');
       expect(result[1]).toEqual(HERO_TWO, ' HERO_TWO should be the second hero');
     }));

  it('getHeroes() while server is down', fakeAsync(() => {
       let result: String[];
       let catchedError: any;
       this.heroService.getHeroes()
           .then((heroes: String[]) => result = heroes)
           .catch((error: any) => catchedError = error);
       this.lastConnection.mockRespond(new Response(new ResponseOptions({
         status: 404,
         statusText: 'URL not Found',
       })));
       tick();
       expect(result).toBeUndefined();
       expect(catchedError).toBeDefined();
     }));
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM