模拟生成的 API 服务
Mocking generated API service
在我们的 Angular 应用程序中,我们正在使用从 API 生成的服务,我们面临着组件或使用它们的自定义服务的单元测试问题。
// Generated code
getCurrentConnection(observe?: 'body', reportProgress?: boolean, options?: {
httpHeaderAccept?: '*/*';
}): Observable<ConnectionResultDto>;
getCurrentConnection(observe?: 'response', reportProgress?: boolean, options?: {
httpHeaderAccept?: '*/*';
}): Observable<HttpResponse<ConnectionResultDto>>;
getCurrentConnection(observe?: 'events', reportProgress?: boolean, options?: {
httpHeaderAccept?: '*/*';
}): Observable<HttpEvent<ConnectionResultDto>>;
在定制服务中的使用
public getConnection(): Observable<ConnectionResultDto> {
return this.connectionServiceAPI.getCurrentConnection('body').pipe(tap(res => this.updateConnectionStatus(res)));
}
并尝试在单元测试中模拟它(我们正在使用 Jest + Spectator + Ng-Mocks)
describe('ConnectionService', () => {
let spectator: SpectatorHttp<ConnectionService>;
const createHttp = createHttpFactory({
service: ConnectionService,
providers: [
MockProvider(ConnectionControllerService, {
getCurrentConnection: ('body') => of(CONNECTION_MOCK) // this throws error displayed below
}),
],
});
这是我们得到的错误(带下划线的 VS Code)
No overload matches this call.
Overload 1 of 3, '(instance: AnyType<ConnectionControllerService>, overrides?: Partial<ConnectionControllerService>): FactoryProvider', gave the following error.
Type 'string' is not assignable to type '{ (observe?: "body", reportProgress?: boolean, options?: { httpHeaderAccept?: "*/*"; }): Observable<ConnectionResultDto>; (observe?: "response", reportProgress?: boolean, options?: { ...; }): Observable<...>; (observe?: "events", reportProgress?: boolean, options?: { ...; }): Observable<...>; }'.
Overload 2 of 3, '(provider: string | InjectionToken<{ getCurrentConnection: string; }>, useValue?: Partial<{ getCurrentConnection: string; }>): FactoryProvider', gave the following error.
Argument of type 'typeof ConnectionControllerService' is not assignable to parameter of type 'string | InjectionToken<{ getCurrentConnection: string; }>'.
Type 'typeof ConnectionControllerService' is missing the following properties from type 'InjectionToken<{ getCurrentConnection: string; }>': _desc, ɵprov
Overload 3 of 3, '(provider: string, useValue?: Partial<{ getCurrentConnection: string; }>): FactoryProvider', gave the following error.
Argument of type 'typeof ConnectionControllerService' is not assignable to parameter of type 'string'.ts(2769)
connectionController.service.d.ts(45, 5): The expected type comes from property 'getCurrentConnection' which is declared here on type 'Partial<ConnectionControllerService>'
(method) getCurrentConnection?(observe?: "body", reportProgress?: boolean, options?: {
httpHeaderAccept?: "*/*";
}): Observable<ConnectionResultDto> (+2 overloads)
知道我们如何才能正确模拟它吗?我尝试指定 getCurrentConnection
方法的每个可选参数,但没有效果。由于未定义结果上的 pipe
运算符,没有覆盖方法的模拟将导致单元测试失败。
这里的问题是 typescript 聚合了所有参数和所有 return 类型。所以它的mock也应该遵循聚合类型。
在这种情况下,(_: 'body') => of(CONNECTION_MOCK)
只是 3 个中的 1 个。
Typescript 期望 _
为 'body' | 'response' | 'events'
,return 类型也是如此:所有 3 个都应该得到尊重。
所有这些都导致使用起来更简单as never
,因为很难实现所需的回调。
MockProvider(ConnectionControllerService, {
getCurrentConnection: (_: 'body') => of(CONNECTION_MOCK),
} as never); // as never
或更弱的选项
// jasmine
MockProvider(ConnectionControllerService, {
getCurrentConnection: jasmine
.createSpy()
.and.returnValue(of(CONNECTION_MOCK)),
});
// jest
MockProvider(ConnectionControllerService, {
getCurrentConnection: jest
.fn()
.mockReturnValue(of(CONNECTION_MOCK)),
});
在我们的 Angular 应用程序中,我们正在使用从 API 生成的服务,我们面临着组件或使用它们的自定义服务的单元测试问题。
// Generated code
getCurrentConnection(observe?: 'body', reportProgress?: boolean, options?: {
httpHeaderAccept?: '*/*';
}): Observable<ConnectionResultDto>;
getCurrentConnection(observe?: 'response', reportProgress?: boolean, options?: {
httpHeaderAccept?: '*/*';
}): Observable<HttpResponse<ConnectionResultDto>>;
getCurrentConnection(observe?: 'events', reportProgress?: boolean, options?: {
httpHeaderAccept?: '*/*';
}): Observable<HttpEvent<ConnectionResultDto>>;
在定制服务中的使用
public getConnection(): Observable<ConnectionResultDto> {
return this.connectionServiceAPI.getCurrentConnection('body').pipe(tap(res => this.updateConnectionStatus(res)));
}
并尝试在单元测试中模拟它(我们正在使用 Jest + Spectator + Ng-Mocks)
describe('ConnectionService', () => {
let spectator: SpectatorHttp<ConnectionService>;
const createHttp = createHttpFactory({
service: ConnectionService,
providers: [
MockProvider(ConnectionControllerService, {
getCurrentConnection: ('body') => of(CONNECTION_MOCK) // this throws error displayed below
}),
],
});
这是我们得到的错误(带下划线的 VS Code)
No overload matches this call.
Overload 1 of 3, '(instance: AnyType<ConnectionControllerService>, overrides?: Partial<ConnectionControllerService>): FactoryProvider', gave the following error.
Type 'string' is not assignable to type '{ (observe?: "body", reportProgress?: boolean, options?: { httpHeaderAccept?: "*/*"; }): Observable<ConnectionResultDto>; (observe?: "response", reportProgress?: boolean, options?: { ...; }): Observable<...>; (observe?: "events", reportProgress?: boolean, options?: { ...; }): Observable<...>; }'.
Overload 2 of 3, '(provider: string | InjectionToken<{ getCurrentConnection: string; }>, useValue?: Partial<{ getCurrentConnection: string; }>): FactoryProvider', gave the following error.
Argument of type 'typeof ConnectionControllerService' is not assignable to parameter of type 'string | InjectionToken<{ getCurrentConnection: string; }>'.
Type 'typeof ConnectionControllerService' is missing the following properties from type 'InjectionToken<{ getCurrentConnection: string; }>': _desc, ɵprov
Overload 3 of 3, '(provider: string, useValue?: Partial<{ getCurrentConnection: string; }>): FactoryProvider', gave the following error.
Argument of type 'typeof ConnectionControllerService' is not assignable to parameter of type 'string'.ts(2769)
connectionController.service.d.ts(45, 5): The expected type comes from property 'getCurrentConnection' which is declared here on type 'Partial<ConnectionControllerService>'
(method) getCurrentConnection?(observe?: "body", reportProgress?: boolean, options?: {
httpHeaderAccept?: "*/*";
}): Observable<ConnectionResultDto> (+2 overloads)
知道我们如何才能正确模拟它吗?我尝试指定 getCurrentConnection
方法的每个可选参数,但没有效果。由于未定义结果上的 pipe
运算符,没有覆盖方法的模拟将导致单元测试失败。
这里的问题是 typescript 聚合了所有参数和所有 return 类型。所以它的mock也应该遵循聚合类型。
在这种情况下,(_: 'body') => of(CONNECTION_MOCK)
只是 3 个中的 1 个。
Typescript 期望 _
为 'body' | 'response' | 'events'
,return 类型也是如此:所有 3 个都应该得到尊重。
所有这些都导致使用起来更简单as never
,因为很难实现所需的回调。
MockProvider(ConnectionControllerService, {
getCurrentConnection: (_: 'body') => of(CONNECTION_MOCK),
} as never); // as never
或更弱的选项
// jasmine
MockProvider(ConnectionControllerService, {
getCurrentConnection: jasmine
.createSpy()
.and.returnValue(of(CONNECTION_MOCK)),
});
// jest
MockProvider(ConnectionControllerService, {
getCurrentConnection: jest
.fn()
.mockReturnValue(of(CONNECTION_MOCK)),
});