Angular 2错误:在Karma-Jasmine测试中没有Http的提供者

Chr*_*ris 19 karma-jasmine angular

即使我的应用程序完美运行且没有错误,我仍然在我的业力测试中收到以下错误.据说没有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)
Run Code Online (Sandbox Code Playgroud)

这是我的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]);
            });
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的简单规范:

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();
  }));
});
Run Code Online (Sandbox Code Playgroud)

该错误似乎是由我的服务引起的,可以在这里看到:

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

  }
}
Run Code Online (Sandbox Code Playgroud)

如果我constructor(public http: Http) { }从服务中删除该语句,测试通过正常,但随后应用程序在浏览器中失败.我已就此做了大量研究,但未能找到解决方案.任何帮助将不胜感激!!

Pau*_*tha 24

其目的TestBed是为测试环境配置一个@NgModule 从头开始.因此,目前你所配置的只是AppComponent,而不是其他任何东西(除了已经在中声明的服务)@Component.providers.

我强烈建议你这样做,而不是试图像在真实环境中那样配置所有东西,只是嘲笑BudgetService.尝试配置Http和模拟它并不是最好的主意,因为您希望在单元测试时尽可能保持外部依赖性尽可能轻.

这是你需要做的

  1. BudgetService.创建一个模拟.我会查看这篇文章.您可以扩展该抽象类,添加您的getBudgets方法

  2. 你需要重写@Component.providers,因为在提到这个岗位

如果你真的只想使用真正的服务Http,那么你需要准备好模拟连接MockBackend.您无法使用真正的后端,因为它依赖于平台浏览器.举个例子,看看这篇文章.在测试组件时,我个人认为这不是一个好主意.在测试您的服务时,您应该这样做.


R2C*_*2C2 14

警告:此解决方案仅在您要测试静态结构时才有效.如果您的测试实际上进行了服务调用(并且您最好还有一些测试),它将无法工作.

您的测试使用自己的模块定义,测试模块,而不是您的AppModule.所以你必须在那里导入HttpModule:

TestBed.configureTestingModule({
    imports: [
        HttpModule
    ],
    declarations: [
        AppComponent
    ]
});
Run Code Online (Sandbox Code Playgroud)

您还可以导入AppModule:

TestBed.configureTestingModule({
    imports: [
        AppModule
    ]
});
Run Code Online (Sandbox Code Playgroud)

这样做的好处是您不必在许多地方添加新组件和模块.它更方便.另一方面,这不太灵活.您可能在测试中导入的数量超出了您的预期.

此外,您具有从低级组件到整个AppModule的依赖关系.事实上,这是一种循环依赖,通常是一个坏主意.所以在我看来,你应该只为那些对你的应用程序至关重要的高级组件这样做.对于可能可重用的更多低级组件,最好在测试规范中明确列出所有依赖项.

  • 这不行.您需要[使用模拟后端](http://stackoverflow.com/a/39483673/2587435). (2认同)

Fil*_*vic 6

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

}
Run Code Online (Sandbox Code Playgroud)

注意:见顶部注意