Tengo una configuración de trabajo con Karma para una aplicación Angular. Actualmente estoy probando 2 servicios diferentes, PerformanceService y DataService, por lo que tengo 2 archivos, performance.service.spec.ts y data.service.spec.ts
Ambos archivos están inicializando TestBed y también configurando un MockHttp para usar al probar los servicios.
TestBed.initTestEnvironment( BrowserDynamicTestingModule, platformBrowserDynamicTesting() ); function createResponse(body) { return Observable.of( new Response(new ResponseOptions({ body: JSON.stringify(body) })) ); } class MockHttp { get() { return createResponse([]); } }Hasta donde yo sé, esto se puede hacer una vez, no es necesario hacerlo para cada servicio, así que creé un src/main.spec.ts y moví ese código allí y lo eliminé de los servicios.
Ahora ejecuto las pruebas y no funciona, me sale un error TypeError: Cannot read property 'injector' of null
¿Alguna idea de por qué sucede esto? Main.spec.ts se ejecuta primero, por lo que, si no me equivoco, TestBed debe inicializarse una vez que podamos probar los servicios.
Gracias
Solo quiero agregar a la respuesta de bobbyg603
Para usuarios de jest , simplemente agregue el siguiente código en setup-jest.js
import { TestBed } from "@angular/core/testing"; import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from "@angular/platform-browser-dynamic/testing"; TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());Nuestro equipo se encontró con el mismo problema. Una solución es extraer la inicialización de TestBed en un archivo separado y protegerlo para que solo se inicialice una vez:
import { TestBed } from "@angular/core/testing"; import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from "@angular/platform-browser-dynamic/testing"; export class TestBedInitializer { static isInitialized: Boolean = false; static getTestBed() { if(!this.isInitialized) { TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); this.isInitialized = true; } return TestBed; } }Luego puede usar el inicializador en el bloque beforeAll para obtener la instancia de TestBed:
import { TestBedInitializer } from './init'; describe('YourSystemUnderTest', () => { let TestBed; beforeAll(() => { TestBed = TestBedInitializer.getTestBed(); }); beforeEach(() => TestBed.configureTestingModule({ imports: [...], providers: [...] })); ... });La ventaja de esta solución es que no depende de que sus suites de prueba se ejecuten en un orden particular. Esto lo libera para ejecutar sus suites individualmente o todas a la vez sin necesidad de realizar cambios en el código.
No es necesario crear su propia clase MockHttp , ya que Angular ya creó una: https://angular.io/docs/ts/latest/api/http/testing/index/MockBackend-class.html
Un ejemplo de uso sería algo como esto:
describe( 'AppleService', () => { let appleService: AppleService, response: Response; beforeEach( () => { TestBed.configureTestingModule( { providers: [ AppleService, { provide: XHRBackend, useClass: MockBackend }, { provide: ComponentFixtureAutoDetect, useValue: true } ], imports: [ HttpModule ] } ) .compileComponents(); } ); it( 'getApples() should return mocked results', async( inject( [ Http, XHRBackend ], ( http: Http, backend: MockBackend ) => { backend.connections.subscribe( ( connection: MockConnection ) => { expect( connection.request.url.match( /\/apple$/ ) ).not.toBe( null ); expect( connection.request.method ).toBe( RequestMethod.Get ); connection.mockRespond( response ); } ); let options = new ResponseOptions( { status: 200, body: [ testApple1, testApple2 ] } ); response = new Response( options ); appleService = new AppleService( resourceService, http ); appleService.getApples().subscribe( apples => { expect( apples ).toEqual( [ testApple1, testApple2 ] ); } ); } ) ) ); } ); TestBed.get() también se puede usar en lugar del envoltorio inject() .