依赖于另一个使用 InjectionToken 的服务的单元测试 Angular 服务
Unit testing Angular service that depends on another service that uses InjectionToken
我正在对 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!
我尝试在测试提供程序中使用空对象而不是字符串,但仍然出现相同的错误。我需要通过其他方式提供这些令牌吗?
我通过向 InjectionTokens 添加工厂函数来解决这个问题,returns 是令牌的默认值。完成后,它默认在根注入器处提供令牌。
由于这两种服务都是由根注入器提供的,而令牌是在 BarModule
的注入器中提供的,因此它们在测试台上彼此不可见,但在整个模块中相互可见由我的应用程序加载,因为它们都存在于模块中。我通过从两个服务中删除 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: () => '' });
作为一个额外的好处,代币现在是可摇树的。有关详细信息,请参阅 here。
我正在对 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!
我尝试在测试提供程序中使用空对象而不是字符串,但仍然出现相同的错误。我需要通过其他方式提供这些令牌吗?
我通过向 InjectionTokens 添加工厂函数来解决这个问题,returns 是令牌的默认值。完成后,它默认在根注入器处提供令牌。
由于这两种服务都是由根注入器提供的,而令牌是在 BarModule
的注入器中提供的,因此它们在测试台上彼此不可见,但在整个模块中相互可见由我的应用程序加载,因为它们都存在于模块中。我通过从两个服务中删除 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: () => '' });
作为一个额外的好处,代币现在是可摇树的。有关详细信息,请参阅 here。