繁体   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