首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >InversifyJS联合测试符号存根

InversifyJS联合测试符号存根
EN

Stack Overflow用户
提问于 2019-11-29 10:34:32
回答 2查看 1.6K关注 0票数 0

我正试图在我的InversifyJS项目上编写单元测试代码。路由测试(使用supertest)工作正常。然后尝试编写sinon stubspy测试,但不可能成功。下面给出我的示例代码:

DemoRoute

代码语言:javascript
复制
@injectable()
class DemoRoute implements IDemoRoute {
 private _demoController:IDemoController;

 constructor( @inject(TYPES.IDemoController) demoController:IDemoController ) {
   this._demoController = demoController;
 }

 create(req: Request, res: Response, next: NextFunction) {
   return this._demoController.create(req.body)
 }
}

Demo.test.ts

代码语言:javascript
复制
import "reflect-metadata";
import * as sinon from "sinon";
const sandbox = sinon.createSandbox();

describe.only("Demo Spec 2", () => {
   demoController = container.get<IDemoController>(TYPES.IDemoController);

   beforeEach((done) => {
      insertStub = sandbox.stub(demoController, 'create');
      done();
   });

   afterEach(() => {
     sandbox.restore();
   });

   it("Should call demo route url", async done => {
     demoRoute  = container.get<IDemoRoute>(TYPES.IDemoRoute);
     const stub =  insertStub.returns(Promise.resolve({ body: { name: "test xyz", code: "test abc"} }));
     const result = await demoRoute.create({body: demoData.validData}, {send: (params) => params});
     expect(stub).to.have.been.called; // throw error
     done();
   });
}

单元测试中的错误

UnhandledPromiseRejectionWarning: AssertionError:期望create至少被调用一次,但从未被调用过

我该如何解决这个问题?提前谢谢。

EN

回答 2

Stack Overflow用户

发布于 2019-12-17 04:50:02

原因是注入到DemoRouteDemoRoute实例和通过以下语句获得的demoController实例:

代码语言:javascript
复制
const demoController = container.get<IDemoController>(TYPES.IDemoController);

它们是两个不同的demoController实例。您刚刚在测试文件中为demoController实例创建了一个存根。

在了解了这一点之后,我们可以为DemoController.prototype.create创建一个存根,它将应用于所有实例。

例如。

demoRoute.ts

代码语言:javascript
复制
import "reflect-metadata";
import { IDemoRoute, IDemoController } from "./interfaces";
import { NextFunction } from "express";
import { TYPES } from "./types";
import { inject, injectable } from "inversify";

@injectable()
export class DemoRoute implements IDemoRoute {
  private _demoController: IDemoController;

  constructor(@inject(TYPES.IDemoController) demoController: IDemoController) {
    this._demoController = demoController;
  }

  create(req: Request, res: Response, next: NextFunction) {
    return this._demoController.create(req.body);
  }
}

demo.test.ts

代码语言:javascript
复制
import "reflect-metadata";
import sinon from "sinon";
import { TYPES } from "./types";
import { IDemoController, IDemoRoute } from "./interfaces";
import { container } from "./inversify.config";
import { DemoController } from "./demoController";
import { expect } from "chai";

const sandbox = sinon.createSandbox();

describe.only("Demo Spec 2", () => {
  const demoController = container.get<IDemoController>(TYPES.IDemoController);
  let insertStub: sinon.SinonStub<any, any>;
  beforeEach(() => {
    insertStub = sandbox.stub(DemoController.prototype, "create");
  });

  afterEach(() => {
    sandbox.restore();
  });

  it("Should call demo route url", async () => {
    const demoData = { validData: {} };
    const demoRoute = container.get<IDemoRoute>(TYPES.IDemoRoute);
    // different demoController instances
    expect(demoRoute["_demoController"]).not.to.be.equal(demoController);
    insertStub.returns(Promise.resolve({ body: { name: "test xyz", code: "test abc" } }));
    const nextStub = sinon.stub();
    const result = await demoRoute.create(
      { body: demoData.validData } as any,
      { send: (params) => params } as any,
      nextStub,
    );
    sinon.assert.calledOnce(insertStub);
  });
});

包含覆盖率报告的单元测试结果:

代码语言:javascript
复制
 Demo Spec 2
    ✓ Should call demo route url


  1 passing (25ms)

---------------------|----------|----------|----------|----------|-------------------|
File                 |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
---------------------|----------|----------|----------|----------|-------------------|
All files            |    96.08 |      100 |       80 |    95.56 |                   |
 demo.test.ts        |    95.83 |      100 |       80 |    95.45 |                31 |
 demoController.ts   |    85.71 |      100 |       50 |       80 |                 7 |
 demoRoute.ts        |      100 |      100 |      100 |      100 |                   |
 inversify.config.ts |      100 |      100 |      100 |      100 |                   |
 types.ts            |      100 |      100 |      100 |      100 |                   |
---------------------|----------|----------|----------|----------|-------------------|

完整的示例源代码:https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/59103140

票数 2
EN

Stack Overflow用户

发布于 2020-04-01 18:29:45

我们能够通过从反版本容器中提取实例的方法,再加上使用sinon.createStubInstance()来模拟构造函数来实现顽固性。看起来是这样的:

代码语言:javascript
复制
describe.only("Demo Spec 2", () => {
   demoController = container.get<IDemoController>(TYPES.IDemoController);
   demoControllerStub = sinon.createStubInstance(IDemoController) as SinonStubbedInstance<IDemoController>;
   beforeEach((done) => {
      insertStub = sinon.stub(demoController, 'create');
      done();
   });

   afterEach(() => {
     sandbox.restore();
   });

   it("Should call demo route url", async done => {
     demoRoute  = container.get<IDemoRoute>(TYPES.IDemoRoute);
     const stub =  insertStub.returns(Promise.resolve({ body: { name: "test xyz", code: "test abc"} }));
     const result = await demoRoute.create({body: demoData.validData}, {send: (params) => params});
     expect(demoControllerStub.create.calledOnce);
     done();
   });
}

为我们工作的另一种方式,我更喜欢,是存根实例,并取消绑定和绑定的存根实例到容器。看起来是这样的:

代码语言:javascript
复制
describe.only("Demo Spec 2", () => {
   demoControllerStub = sinon.createStubInstance(IDemoController);

   container.unbind(IDemoController);
   container.bind(IDemoController).toConstantValue(demoControllerStub);

   beforeEach((done) => {
      demoControllerStub.create.reset();
      done();
   });

   it("Should call demo route url", async done => {
     demoRoute  = container.get<IDemoRoute>(TYPES.IDemoRoute);
     const stub =  insertStub.returns(Promise.resolve({ body: { name: "test xyz", code: "test abc"} }));
     const result = await demoRoute.create({body: demoData.validData}, {send: (params) => params});
     sinon.assert.calledWith(demoControllerStub.create, sinon.match({body: demoData.validData});
     done();
   });
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59103140

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档