Sinon.js 带参数的间谍函数

Spy function with params by Sinon.js

我正在尝试编写一些使用 typeorm 的代码的单元测试,而无需访问数据库。 我正在为 spy/stub/mock 使用 sinon。 这是我的职能。

  async updateDoingToFailedWithLock(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.manager
      .getRepository(Report)
      .createQueryBuilder("report")
      .useTransaction(true)
      .setLock("pessimistic_write")
      .update(Report)
      .set({ status: ReportStatus.FAILED })
      .where(`(status = "doing")`)
      .execute();
  }

我已经编写了一个假测试来确保 execute() 是通过间谍函数调用的。 但是我想测试这些函数的参数createQueryBuilder...,确保参数是正确的。 我查看了 sinon 文档,似乎 sinon 通过 API: spy().withArgs(arg1, arg2...) 支持测试参数。

但我不确定如何正确地监视我的函数。

describe("updateDoingToFailedWithLock()", (): void => {
    let sandbox: Sinon.SinonSandbox;

    beforeEach(() => (sandbox = Sinon.createSandbox()));
    afterEach(() => sandbox.restore);

    it("should be success", async (): Promise<void> => {
      const fakeManager = {
        getRepository: () => {
          return fakeManager;
        },
        createQueryBuilder: () => {
          return fakeManager;
        },
        useTransaction: () => {
          return fakeManager;
        },
        setLock: () => {
          return fakeManager;
        },
        update: () => {
          return fakeManager;
        },
        set: () => {
          return fakeManager;
        },
        where: () => {
          return fakeManager;
        },
        execute: () => {},
      };
      const fakeQueryRunner = {
        manager: fakeManager,
      };
      const connection = new typeorm.Connection({ type: "mysql" });
      const reportService = new ReportService();
      sandbox.stub(connection, "createQueryRunner").callsFake((): any => {
        return fakeQueryRunner;
      });

      const queryRunner = connection.createQueryRunner();
      const spy = sandbox.spy(fakeManager, "execute");

      reportService.updateDoingToFailedWithLock(queryRunner);
      expect(spy.calledOnce).be.true;
    });
  });

欢迎任何帮助。提前致谢!

我看到了你的代码,有一些地方可以改进:

  • returnsThis()代替return fakeManager
  • 调用updateDoingToFailedWithLock时不要忘记await
describe("updateDoingToFailedWithLock()", (): void => {
  let sandbox: sinon.SinonSandbox;

  beforeEach(() => (sandbox = sinon.createSandbox()));
  afterEach(() => sandbox.restore);

  it("should be success", async (): Promise<void> => {

    // using returnsThis()
    const fakeManager = {
      getRepository: sandbox.stub().returnsThis(),
      createQueryBuilder: sandbox.stub().returnsThis(),
      useTransaction: sandbox.stub().returnsThis(),
      setLock: sandbox.stub().returnsThis(),
      update: sandbox.stub().returnsThis(),
      set: sandbox.stub().returnsThis(),
      where: sandbox.stub().returnsThis(),
      execute: sandbox.stub().returnsThis(),      
    }

    const fakeQueryRunner = {
      manager: fakeManager,
    };

    const reportService = new ReportService();

    // having await here is important
    await reportService.updateDoingToFailedWithLock(fakeQueryRunner);


    expect(fakeManager.execute.calledOnce).to.be.true;
    expect(fakeManager.createQueryBuilder.calledWith('report')).to.be.true;
  });
});

希望对您有所帮助