我尝试构建一个依赖于提供InjectorToken的Injector的Angular组件:
import { Component, Injector, InjectionToken } from '@angular/core';
const TOKEN = new InjectionToken<string>('token');
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent {
constructor(injector: Injector) {
injector.get(TOKEN);
}
}
但是,我无法为此组件运行测试并出现以下错误:
NullInjectorError: StaticInjectorError(DynamicTestModule)[InjectionToken token]:
StaticInjectorError(Platform: core)[InjectionToken token]:
NullInjectorError: No provider for InjectionToken token!
以下在TestBed中提供Injector的方法不起作用:
TestBed.configureTestingModule({
declarations: [ TestComponent ],
providers: [
{ provide: Injector, useValue: Injector.create({providers: [
{
provide: new InjectionToken<string>('token'),
useValue: '',
deps: []
}
]}) }
]
})
如何正确设置测试环境?
答案 0 :(得分:0)
我也无法按照您在示例中所做的方式来建立规范,但是有一种更简单的方法。我认为您的问题有两个来源。首先是要在测试时构建新的InjectorToken。重要的事情在这里说明:
const inj1 = new InjectorToken<string>('token');
const inj2 = new InjectorToken<string>('token');
console.log(inj1 === inj2); // logs false
日志将为false
,即使它们使用相同的字符串,但它们是不同的对象。我建议构建一个注入令牌并将其导出为常量,如下所示:
export const TOKEN = new InjectionToken<string>('token');
然后将TOKEN
导入到您需要注入的任何位置。
第二个问题是您要使用新的注射器模拟注射器。接线很多。我根本无法正常工作。但是您可以这样简化规格:
import { TOKEN } from './token.const';
describe('token', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ TestComponent ],
providers: [
{ provide: TOKEN, useValue: '' }
]
});
});
});
这样做,您可以使用现有的注入器,但是可以模拟注入的内容。这通常是目标。
您可能还想考虑在组件中使用注入装饰器,如下所示:
import { Component, Inject, InjectionToken } from '@angular/core';
import { TOKEN } from './token.const';
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent {
constructor(@Inject(TOKEN) value: any) {}
}
这是获得注入值的一种更简单的方法,并且更清洁。您将以完全相同的方式编写规范。
答案 1 :(得分:0)
只需提供您要注入的令牌。注射器将自动为您创建。您不必自己创建它。
// app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'playground-app';
config: string;
constructor(private injector: Injector) {
this.config = injector.get('CONFIG_TOKEN');
}
}
// app.component.spec.ts
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
providers: [
{ provide: 'CONFIG_TOKEN', useValue: 'Test' }
]
}).compileComponents();
}));
it(`should inject the config`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.config).toEqual('Test');
});
});