如何在玩笑单元测试中模拟私有 ngxs 状态服务依赖项/属性 问题最终解决方案

问题描述

我正在使用 ngxs 来管理我的应用程序的状态。

@State<EmployeesstateModel>({
  name: 'employees',defaults: {
    // ...
  }
})
@Injectable({
  providedIn: 'root'
})
export class Employeesstate {
  constructor(private employeesService: EmployeesService) {
  }

  @Action(GetEmployeesList)
  async getEmployeesList(ctx: StateContext<EmployeesstateModel>,action: GetEmployeesList) {

    const result = await this.employeesService
      .getEmployeeListQuery(0,10).toPromise();
    // ...
  }
}

问题

我不明白如何在测试中使用 jest 来模拟 EmployeesService 依赖项。与 NGXS 测试相关的文档也没有提供任何示例。

我刚刚开始测试 angular/node 应用程序,所以我不知道我在做什么。

我按照从 this SO question 学到的知识进行了以下测试。

describe('EmployeesstateService',() => {
  let store: Store;
  let employeesServiceStub = {} as EmployeesService;

  beforeEach(() => {
    employeesServiceStub = {
      getEmployeeListQuery: jest.fn()
    };
    Testbed.configureTestingModule({
      imports: [
        HttpClientTestingModule,NgxsModule.forRoot([Employeesstate])
      ],providers: [

        { provide: EmployeesService,useFactory: employeesServiceStub }
      ]
    });
    store = Testbed.inject(Store);
    Testbed.inject(EmployeesService);
  });

  it('gets a list of employees',async () => {
    employeesServiceStub = {
      getEmployeeListQuery: jest.fn((skip,take) => [])
    };

    await store.dispatch(new GetEmployeesList()).toPromise();

    const list = store.selectSnapshot(state => state.employees.employeesList);
    expect(list).toStrictEqual([]);
  });
});

当我尝试运行测试时,这会导致错误 TypeError: provider.useFactory.apply is not a function

此外,当我在 employeesServiceStub 函数中设置 beforeEach 的值时,它会引发错误,指出我分配的值缺少实际 {{1} 中的其余属性}.本质上要求我对服务进行完整的模拟实现。这对我来说是非常低效的,因为在每次测试中,我都需要为不同的函数定义不同的模拟实现。

EmployeesService

理想情况下,在每个测试中,我应该能够在每个测试中为 TS2740: Type '{ getEmployeeListQuery: Mock ; }' is missing the following properties from type 'EmployeesService': defaultHeaders,configuration,encoder,basePath,and 8 more. 的模拟函数定义不同的返回值,而不必定义该测试不需要的函数的模拟版本.

由于 EmployeesService 中的函数是异步函数,我也不知道如何为函数定义异步返回值。如果有人能对此有所了解,我将不胜感激。

最终解决方

基于 answer given by Mark Whitfield,我进行了以下更改以解决我的问题。

EmployeesService

解决方法

您的示例中使用 useFactory 的提供程序定义不正确。 你可以把它改成这样:

providers: [
  { provide: EmployeesService,useFactory: () => employeesServiceStub }
]

您可以将 useValue 用于您的提供者,但这意味着您无法重新分配您在 beforeEach 中初始化的模拟,而是必须对其进行变异:

providers: [
  { provide: EmployeesService,useValue: employeesServiceStub }
]
// then in your test...
employeesServiceStub..getEmployeeListQuery = jest.fn(....

employeesServiceStub 的重新分配实际上可能仍然是您的测试的问题,因此您可以改为改变对象,或将 TestBed 设置移动到您的测试中。

注意:模拟 NGXS 状态的提供者与任何其他 Angular 服务相同。

关于您问题的第二部分,如果您在说 async 时指的是 observable(我可以从您的用法中推断出),那么您可以创建一个 observable 作为结果返回。例如:

import { of } from 'rxjs';
// ...
employeesServiceStub.getEmployeeListQuery = jest.fn((skip,take) => of([]))

附注。如果您在说 async 时确实指的是承诺,那么您只需将您的方法标记为 async 以获得承诺作为结果。例如:

employeesServiceStub.getEmployeeListQuery = jest.fn(async (skip,take) => [])