如何使用Mocha、Chai与Sinon模拟sequelizeConnector、mongoConnector返回结果
解决方案
你可以通过proxyquire替换模块依赖,配合Sinon打桩来完全mock掉两个数据库连接工具的实现,完全避免触发真实数据库连接,同时还可以验证这两个连接器是否被正确调用。
步骤1:安装依赖
如果还没装proxyquire的话先安装:
npm install proxyquire --save-dev
步骤2:修改测试代码
完整测试代码如下:
const chai = require("chai"); const sinon = require("sinon"); const sinonChai = require("sinon-chai"); const proxyquire = require("proxyquire"); const express = require("express"); const { expect } = chai; chai.should(); chai.use(sinonChai); describe("CreateServer", () => { // 预先声明要mock的依赖 let mockSequelizeConnector; let mockMongoConnector; let mockLogger; let mockDatabases; let CreateServer; beforeEach(() => { // 初始化所有stub mockSequelizeConnector = sinon.stub(); mockMongoConnector = sinon.stub().returns(sinon.stub()); // 模拟返回中间件函数 mockLogger = { info: sinon.stub(), error: sinon.stub() }; mockDatabases = { sequelizeSupportDialect: ["mysql", "postgres", "mariadb", "mssql"], mongodbDialect: "mongodb" }; // 用proxyquire替换createServer中的依赖 CreateServer = proxyquire("./createServer", { "./sequelizeConnector": mockSequelizeConnector, "./mongoConnector": mockMongoConnector, "custom-error-exceptions": { logger: { logger: mockLogger } }, // 对应mock原代码用到的databases常量,如果是从其他模块引入就改对应引入路径 "databases": mockDatabases }); // mock express实例的use方法方便后续验证 sinon.stub(express, "express").returns({ use: sinon.stub() }); }); afterEach(() => { // 每次测试后清空stub,避免用例互相影响 sinon.restore(); }); describe("choosingDatabase", () => { it("无数据库配置时打印对应日志", () => { const server = new CreateServer({}); server.choosingDatabase(); expect(mockLogger.info).to.have.been.calledWith("No database config found"); }); it("传入支持的sequelize方言时调用sequelizeConnector", () => { const testConfig = { dbConfig: { dialect: "mysql" } }; const testModels = { user: {} }; const server = new CreateServer({ config: testConfig, models: testModels }); server.choosingDatabase(); expect(mockLogger.info).to.have.been.calledWith("Using sequelize dialect mysql database"); expect(mockSequelizeConnector).to.have.been.calledOnceWith( server.app, testConfig, mockLogger, testModels ); }); it("传入mongodb方言时调用mongoConnector并注册中间件", () => { const testConfig = { dbConfig: { dialect: "mongodb" } }; const testModels = { goods: {} }; const server = new CreateServer({ config: testConfig, models: testModels }); const mockMiddleware = mockMongoConnector.returnValues[0]; server.choosingDatabase(); expect(mockLogger.info).to.have.been.calledWith("Using mongodb database"); expect(mockMongoConnector).to.have.been.calledOnceWith( server.app, testConfig, mockLogger, testModels ); expect(server.app.use).to.have.been.calledOnceWith(mockMiddleware); }); it("传入不支持的方言时打印错误日志", () => { const testConfig = { dbConfig: { dialect: "wrong" } }; const server = new CreateServer({ config: testConfig }); server.choosingDatabase(); expect(mockLogger.error).to.have.been.calledWith("Dialect you're choosing ins'nt supported"); }); }); })
关键说明
- 用
proxyquire可以在加载createServer.js的时候,直接替换它引入的外部依赖模块,不需要修改原业务代码 - 所有外部依赖(logger、databases常量、两个连接器)都被mock成了Sinon stub,不会执行真实的连接逻辑
- 原测试中的三个用例逻辑重复,仅验证了方法被调用,上述代码已经覆盖了四个分支,同时验证了入参、日志、后续调用逻辑是否正确
内容的提问来源于stack exchange,提问作者Cristopher Sugianto
相关产品推荐
相关产品推荐

