如何用 Jest 模拟 Sequelize?

Cat*_*ora 10 unit-testing mocking sequelize.js typescript jestjs

我正在尝试为调用 Sequelize 来创建数据库的代码编写单元测试。

我一生都无法弄清楚如何模拟对 Sequelize 的调用,以便我可以断言他们已经正确创建了数据库表。

我点击 Sequelize 的代码如下:

import { Sequelize, DataTypes } from "sequelize";

export setup_db = async (db_path: string) => {
    //Get read/write connection to database
    const sequelizeContext = new Sequelize({
      dialect: "sqlite",
      storage: db_path,
    });

    //Check if connection is secure, throw error if not
    try {
      await sequelizeContext.authenticate();
    } catch (err) {
      throw err;
    }

    //Define first table
    const Table1 = sequelizeContext.define(
      "table1",
      {
        fieldName_1: {
          type: DataTypes.STRING
        }
      },
      { tableName: "table1" }
    );

    //Define second table
    const Table2 = sequelizeContext.define(
      "table2", 
      {
        fieldName_1: {
          type: DataTypes.STRING
        },
      {tablename: "table2"}
    });

    //Define relationship between tables... each Gamertag hasMany wzMatches
    Table1.hasMany(Table2);

    await Table1.sync();
    await Table2.sync();
  };
Run Code Online (Sandbox Code Playgroud)

理想情况下,我想断言它define被正确调用,hasMany被正确调用,并且sync被每个数据库调用。

我目前的测试代码如下,尽管它抛出了一个关于

无法监视身份验证属性,因为它不是函数;改为未定义。

import { setup_db } from "../../core/dataManager";
const Sequelize = require("sequelize").Sequelize;

describe("DataManager.setup_db", () => {
  it("should call sequelize to correctly set up databases", async () => {
    //Arrange
    const authenticateSpy = jest.spyOn(Sequelize, "authenticate");

    //Act
    await setup_db("path/to/db.db");

    //Assert
    expect(authenticateSpy).toHaveBeenCalledTimes(1);
  });
});
Run Code Online (Sandbox Code Playgroud)

我不确定是否spyOn是正确的调用方法,或者我是否可以/如何使用它jest.mock来模拟和检查对Sequelize.

sli*_*wp2 14

我将使用jest.mock(moduleName,factory,options)手动模拟sequelize模块。

\n

单元测试解决方案:

\n

index.ts:

\n
import { Sequelize, DataTypes } from \'sequelize\';\n\nexport const setup_db = async (db_path: string) => {\n  const sequelizeContext = new Sequelize({\n    dialect: \'sqlite\',\n    storage: db_path,\n  });\n\n  try {\n    await sequelizeContext.authenticate();\n  } catch (err) {\n    throw err;\n  }\n\n  const Table1 = sequelizeContext.define(\n    \'table1\',\n    {\n      fieldName_1: {\n        type: DataTypes.STRING,\n      },\n    },\n    { tableName: \'table1\' },\n  );\n\n  const Table2 = sequelizeContext.define(\n    \'table2\',\n    {\n      fieldName_1: {\n        type: DataTypes.STRING,\n      },\n    },\n    { tableName: \'table2\' },\n  );\n\n  (Table1 as any).hasMany(Table2);\n\n  await Table1.sync();\n  await Table2.sync();\n};\n
Run Code Online (Sandbox Code Playgroud)\n

index.test.ts:

\n
import { setup_db } from \'./\';\nimport { Sequelize, DataTypes } from \'sequelize\';\nimport { mocked } from \'ts-jest/utils\';\n\njest.mock(\'sequelize\', () => {\n  const mSequelize = {\n    authenticate: jest.fn(),\n    define: jest.fn(),\n  };\n  const actualSequelize = jest.requireActual(\'sequelize\');\n  return { Sequelize: jest.fn(() => mSequelize), DataTypes: actualSequelize.DataTypes };\n});\n\nconst mSequelizeContext = new Sequelize();\n\ndescribe(\'64648688\', () => {\n  afterAll(() => {\n    jest.resetAllMocks();\n  });\n  it(\'should setup db correctly\', async () => {\n    const mTable1 = { hasMany: jest.fn(), sync: jest.fn() };\n    const mTable2 = { sync: jest.fn() };\n    mocked(mSequelizeContext.define).mockImplementation((modelName): any => {\n      switch (modelName) {\n        case \'table1\':\n          return mTable1;\n        case \'table2\':\n          return mTable2;\n      }\n    });\n    await setup_db(\':memory:\');\n    expect(Sequelize).toBeCalledWith({ dialect: \'sqlite\', storage: \':memory:\' });\n    expect(mSequelizeContext.authenticate).toBeCalled();\n    expect(mSequelizeContext.define).toBeCalledWith(\n      \'table1\',\n      {\n        fieldName_1: {\n          type: DataTypes.STRING,\n        },\n      },\n      { tableName: \'table1\' },\n    );\n    expect(mSequelizeContext.define).toBeCalledWith(\n      \'table2\',\n      {\n        fieldName_1: {\n          type: DataTypes.STRING,\n        },\n      },\n      { tableName: \'table2\' },\n    );\n    expect(mTable1.hasMany).toBeCalledWith(mTable2);\n    expect(mTable1.sync).toBeCalledTimes(1);\n    expect(mTable2.sync).toBeCalledTimes(1);\n  });\n});\n
Run Code Online (Sandbox Code Playgroud)\n

单元测试结果:

\n
 PASS  src/stackoverflow/64648688/index.test.ts (16.442s)\n  64648688\n    \xe2\x9c\x93 should setup db correctly (11ms)\n\n----------|----------|----------|----------|----------|-------------------|\nFile      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |\n----------|----------|----------|----------|----------|-------------------|\nAll files |    91.67 |      100 |      100 |    90.91 |                   |\n index.ts |    91.67 |      100 |      100 |    90.91 |                12 |\n----------|----------|----------|----------|----------|-------------------|\nTest Suites: 1 passed, 1 total\nTests:       1 passed, 1 total\nSnapshots:   0 total\nTime:        20.184s\n
Run Code Online (Sandbox Code Playgroud)\n