#typescript #unit-testing #jestjs #mocking #sequelize.js
#typescript #модульное тестирование #jestjs #издевательство #sequelize.js
Вопрос:
Я пытаюсь написать модульные тесты для кода, который вызывает 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, потому что оно не является функцией; вместо этого задано undefined.
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
.
Ответ №1:
Я собираюсь использовать 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