如何用Jest模拟Sequelize? [英] How to mock Sequelize with Jest?

查看:131
本文介绍了如何用Jest模拟Sequelize?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写代码的单元测试,这些代码调用Sequelize创建数据库.

I am trying to write unit tests for code which makes calls to Sequelize to create a database.

我终生无法弄清楚如何模拟对Sequelize的调用,以便断言它们已正确创建了数据库表.

I cannot for the life of me figure out how to mock out calls to Sequelize such that I can assert they have created the database tables correctly.

我命中Sequelize的代码如下:

My code which hits Sequelize is as follows:

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.

Ideally, I would like to assert that define was called properly, hasMany was called properly, and sync was called for each database.

我的测试代码目前如下,尽管它引发了错误

My test code currently is as follows, although it throws an error about

因为它不是函数,所以无法监视authenticate属性;取而未定义.

Cannot spy the authenticate property because it is not a function; undefined given instead.

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的调用.

I'm not sure if spyOn is the right method to call, or whether I can/how I can use jest.mock to mock out and inspect calls to Sequelize.

推荐答案

我将使用 jest.mock(模块名称,工厂,选项)以手动模拟sequelize模块.

I am going to use jest.mock(moduleName, factory, options) to mock sequelize module manually.

单元测试解决方案:

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

这篇关于如何用Jest模拟Sequelize?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆