我正在尝试编写代码的单元测试,这些代码调用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();
};
理想情况下,我想断言define
被正确调用,hasMany
被正确调用,并且sync
被每个数据库调用。
我的测试代码目前如下,尽管它会引发错误
因为它不是函数,所以无法监视authenticate属性;取而未定义。
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);
});
});
我不确定spyOn
是正确的调用方法,还是不确定是否可以/如何使用jest.mock
模拟并检查对Sequelize
的调用。
答案 0 :(得分:0)
我将使用jest.mock(moduleName, factory, options)手动模拟sequelize
模块。
单元测试解决方案:
index.ts
:
import { Sequelize, DataTypes } from 'sequelize';
export const setup_db = async (db_path: string) => {
const sequelizeContext = new Sequelize({
dialect: 'sqlite',
storage: db_path,
});
try {
await sequelizeContext.authenticate();
} catch (err) {
throw err;
}
const Table1 = sequelizeContext.define(
'table1',
{
fieldName_1: {
type: DataTypes.STRING,
},
},
{ tableName: 'table1' },
);
const Table2 = sequelizeContext.define(
'table2',
{
fieldName_1: {
type: DataTypes.STRING,
},
},
{ tableName: 'table2' },
);
(Table1 as any).hasMany(Table2);
await Table1.sync();
await Table2.sync();
};
index.test.ts
:
import { setup_db } from './';
import { Sequelize, DataTypes } from 'sequelize';
import { mocked } from 'ts-jest/utils';
jest.mock('sequelize', () => {
const mSequelize = {
authenticate: jest.fn(),
define: jest.fn(),
};
const actualSequelize = jest.requireActual('sequelize');
return { Sequelize: jest.fn(() => mSequelize), DataTypes: actualSequelize.DataTypes };
});
const mSequelizeContext = new Sequelize();
describe('64648688', () => {
afterAll(() => {
jest.resetAllMocks();
});
it('should setup db correctly', async () => {
const mTable1 = { hasMany: jest.fn(), sync: jest.fn() };
const mTable2 = { sync: jest.fn() };
mocked(mSequelizeContext.define).mockImplementation((modelName): any => {
switch (modelName) {
case 'table1':
return mTable1;
case 'table2':
return mTable2;
}
});
await setup_db(':memory:');
expect(Sequelize).toBeCalledWith({ dialect: 'sqlite', storage: ':memory:' });
expect(mSequelizeContext.authenticate).toBeCalled();
expect(mSequelizeContext.define).toBeCalledWith(
'table1',
{
fieldName_1: {
type: DataTypes.STRING,
},
},
{ tableName: 'table1' },
);
expect(mSequelizeContext.define).toBeCalledWith(
'table2',
{
fieldName_1: {
type: DataTypes.STRING,
},
},
{ tableName: 'table2' },
);
expect(mTable1.hasMany).toBeCalledWith(mTable2);
expect(mTable1.sync).toBeCalledTimes(1);
expect(mTable2.sync).toBeCalledTimes(1);
});
});
单元测试结果:
PASS src/stackoverflow/64648688/index.test.ts (16.442s)
64648688
✓ should setup db correctly (11ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 91.67 | 100 | 100 | 90.91 | |
index.ts | 91.67 | 100 | 100 | 90.91 | 12 |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 20.184s