1

我正在对一个看起来像这样的 Angular 服务进行单元测试:

/* data.service.ts */
import { Injectable } from '@angular/core';

import { FooService } from './foo.service';
import { Data } from './data.model';

@Injectable({
  providedIn: 'root'
})
export class DataService {
  constructor(private fooService: FooService) {}

  addData(data: Data) {
    return this.fooService.getActiveFoo().addData(data);
  }
}

FooService是同一模块中的服务。它使用 InjectionTokens 注入一些值。

/* foo.service.ts */
import { Inject, Injectable } from '@angular/core';

import { KEY1, KEY2 } from './tokens';
import { Foo } from './foo.ts';

@Injectable({
  providedIn: 'root'
})
export class FooService{

  activeFoo: Foo; 

  constructor(@Inject(KEY1) private key1: string, @Inject(KEY2) private key2: string) {}

  ...

  getActiveFoo() {
    return this.activeFoo; 
 }
}


/* tokens.ts */
import { InjectionToken } from '@angular/core';

export const KEY1 = new InjectionToken('KEY_1');
export const KEY2 = new InjectionToken('KEY_2');

所有三个文件都是同一个模块的一部分,该模块的设置如下:

/* bar.module.ts */
import { ModuleWithProviders, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { KEY1, KEY2 } from './tokens';
import { DataService } from './data.service';
import { FooService } from './foo.service';

@NgModule({
  imports: [CommonModule],
})
export class BarModule {
  static forRoot(key1Val: string, key2Val: string): ModuleWithProviders {
    return {
      ngModule: BarModule,
      providers: [
        DataService,
        FooService,
        { provide: KEY1, useValue: key1Val},
        { provide: KEY2, useValue: key2Val}
      ]
    };
  }
}

这在应用程序本身中运行良好。现在我正在data.service.ts为提供的 InjectionTokens 编写单元测试并遇到问题。

/* data.service.spec.ts */
import { TestBed, inject } from '@angular/core/testing';

import { DataService } from './data.service';
import { FooService } from './foo.service';
import { KEY1, KEY2 } from './tokens';

describe('DataService', () => {
  const mockFooService = jasmine.createSpyObj(['getActiveFoo']);

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        DataService,
        { provide: FooService, useValue: mockFooService },
        { provide: KEY1, useValue: 'abc' },
        { provide: KEY2, useValue: '123' }
      ]
    });
  });

  it('should be created', inject([DataService], (service: DataService) => {
    expect(service).toBeTruthy();
  }));
});

当我运行测试时,我收到一条错误消息

Error: StaticInjectorError(DynamicTestModule)[FooService -> InjectionToken KEY_1]: 
  StaticInjectorError(Platform: core)[FooService -> InjectionToken KEY_1]: 
    NullInjectorError: No provider for InjectionToken KEY_1!

我尝试在测试提供程序中使用空对象而不是字符串,但仍然得到相同的错误。我需要提供这些令牌的另一种方式吗?

4

1 回答 1

1

我通过将工厂函数添加到返回令牌默认值的 InjectionTokens 解决了这个问题。完成此操作后,它默认在根注入器处提供令牌。

由于这两种服务都是由根注入器提供的,并且令牌是在BarModule's 注入器中提供的,因此它们在测试床中彼此不可见,但是当我的应用程序加载整个模块时,它们都存在在模块中。我通过providedIn从两个服务中删除并保留原始令牌来确认这一点。

我的代币现在看起来像

/* tokens.ts */
import { InjectionToken } from '@angular/core';

export const KEY1 = new InjectionToken<string>('KEY_1', {factory: () => '' });
export const KEY2 = new InjectionToken<string>('KEY_2', {factory: () => '' });

作为一个额外的好处,令牌现在可以摇树。请参阅此处了解更多信息。

于 2018-05-31T22:52:46.277 回答