角度测试:如何提供喷油器?

时间:2019-10-30 10:07:33

标签: angular testing

我尝试构建一个依赖于提供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: []
      }
    ]}) }
  ]
})

如何正确设置测试环境?

2 个答案:

答案 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');
  });

});