unit test run component angular karma-jasmine

test - Error angular 2: no hay proveedor de Http en la prueba de karma-jazmín



testing angular 7 (5)

Sigo recibiendo el siguiente error en mi prueba de karma, aunque mi aplicación funciona perfectamente sin errores. Está diciendo que no hay proveedor para HTTP. Estoy usando la import { HttpModule } from ''@angular/http''; en mi archivo app.module.ts y agregarlo a la matriz de importaciones. El error de karma se parece a lo siguiente:

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)

Aquí está mi archivo 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]); }); } }

Aquí está mi simple especificación:

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

El error parece ser causado por mi servicio, que se puede ver aquí:

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

Si elimino la declaración del constructor(public http: Http) { } pública del servicio, la prueba pasa bien, pero la aplicación falla en el navegador. He investigado bastante sobre esto y no he podido encontrar la solución. Cualquier ayuda sería muy apreciada !!


En Angular 4+

La respuesta de RC2C funcionó para mí :) ¡Gracias!

Precaución : esto solo funcionará si realmente no está llamando a su servicio. Solo funciona si desea probar la estructura estática.

Solo quería agregar que para la versión Angular 4 (y más alta, probablemente) debería importar HttpClientModule a su banco de pruebas, para que se vea así:

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

Precaución : ver la precaución superior


El propósito de TestBed es configurar un @NgModule desde cero para el entorno de prueba. Por lo tanto, actualmente todo lo que ha configurado es AppComponent , y nada más (excepto el servicio que ya está declarado en @Component.providers .

Sin embargo, lo que sugiero que hagas, en lugar de intentar configurar todo como lo harías en un entorno real, es simplemente BudgetService . Tratar de configurar el Http y el simulacro no es la mejor idea, ya que desea mantener las dependencias externas lo más livianas posible cuando se realiza la prueba de la unidad.

Esto es lo que necesitas hacer

  1. Crear un simulacro para el BudgetService . Me gustaría ver esta publicación . Simplemente puede extender esa clase abstracta, agregando su método getBudgets

  2. Debe anular los @Component.providers , como se menciona en esta publicación

Si realmente solo quieres usar el servicio real y el Http , entonces debes estar preparado para MockBackend conexiones en el MockBackend . No puedes usar el backend real, ya que depende del navegador de la plataforma. Para un ejemplo, echa un vistazo a esta publicación . Personalmente, no creo que sea una buena idea cuando se prueban componentes. Al probar su servicio, es cuando debe hacerlo.


Importe HttpModule en app.module.ts y resolverá su problema.

import { HttpModule } from ''@angular/http''; @NgModule({ imports: [HttpModule] }) ...


Una alternativa a burlarse del servicio como se describe en la respuesta de peeskillet , es usar el Back- back simulado proporcionado por angular .

El documento API contiene el siguiente ejemplo:

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


Precaución : esta solución solo funciona si desea probar la estructura estática. No funcionará si su prueba realmente hace llamadas de servicio (y es mejor que también tenga algunas de esas pruebas).

Su prueba utiliza una definición de módulo propio, un módulo de prueba y no su módulo de aplicación. Así que tienes que importar HttpModule allí también:

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

También puedes importar tu AppModule:

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

Esto tiene la ventaja de que no tiene que agregar nuevos componentes y módulos en muchos lugares. Es más conveniente. Por otro lado esto es menos flexible. Es posible que esté importando más de lo que desearía en su prueba.

Además, tiene una dependencia desde su componente de bajo nivel a todo el Módulo de Aplicación. De hecho, eso es una especie de dependencia circular que normalmente es una mala idea. En mi opinión, solo debería hacerlo para componentes de alto nivel que de todos modos son muy importantes para su aplicación. Para más componentes de bajo nivel que pueden ser incluso reutilizables, mejor enumere todas las dependencias explícitamente en la especificación de prueba.