用Jest模拟TypeDI服务

时间:2020-05-07 13:27:33

标签: node.js typescript unit-testing jestjs

我将Node与TypeScript,TypeDI和Jest一起使用。 我正在创建相互依赖的服务,比如说:

@Service()
export class MainService{
constructor(private secondService: SecondService){}
public someMethod(someString: string) // implementation depends on secondService
}

@Service()
export class SecondService{
constructor(private thirdService: ThirdService){}
}

@Service()
export class ThirdService{
constructor(){}
}

我想测试MainService,但是要实例化它,我需要传递依赖关系,并且该依赖关系还需要另一个依赖关系。 我试图这样做,它可以工作,但是很丑:

const secondService = new SecondService(new ThirdService());
jest
    .spyOn(secondService, "someMethod")
    .mockImplementation((someString: string) => {
        // do something
        return something;
    });
const mainService = new MainService(secondService);
// use mainService in tests

当然,创建新的依赖项实例并非总是一种选择,并且在具有很多依赖项时,默认也不是一种选择。

我认为它应该更像:

const secondService = SomeMockFactory.create(SecondService);

但是我在切断依赖关系时找不到任何方法来创建模拟。我尝试使用

const secondService = jest.genMockFromModule("path/to/second/service");

但是在尝试spyOn secondService方法后,TS抛出“ someMethod”不是函数的错误。 我想念/做错了什么?除了Jest,我还需要其他库吗?

1 个答案:

答案 0 :(得分:0)

一段时间后,我发现了如何使用默认的玩笑行为来做到这一点。

首先,您需要在path/to/second/service/__mocks__中创建SecondService的模拟,例如:

// path/to/second/service/__mocks__/SecondService.ts
const mock = jest.fn().mockImplementation(() => ({
  async thingSecondServiceDoInFirstService(
    param: number
  ): number {
    return 1;

}));
export default mock;

SecondService必须是默认导出,例如:

// path/to/second/service/SecondService.ts
    @Service()
export default class SecondService {
constructor(private thirdService: ThirdService) {}
  async thingSecondServiceDoInFirstService(
    param: number
  ): number {
    return this.thirdService.thingThirdServiceDoInSecond(param);
  }
}

在测试文件中,您必须先导入jest.mock,然后再导入SecondService,然后从模拟中创建SecondService实例:

jest.mock("path/to/second/service/SecondService");
import SecondService from "path/to/second/service/SecondService";
import MainService from "path/to/main/service/MainService";

describe("Test main service", () => {

  const SecondServiceMock = <jest.Mock<SecondService>>SecondService;
  let secondService = new SecondServiceMock();

  beforeEach(() => {
    mainService = new MainService(secondService);
  });

// test logic...
}

根据要求,不再需要ThirdService。