typescript - Hvordan mocke Sequelize med Jest?


Jeg prøver å skrive enhetstester for kode som gjør kall til Sequelize for å opprette en database.

Jeg kan for mitt liv ikke finne ut hvordan jeg skal etterligne kall til Sequelize slik at jeg kan påstå at de har opprettet databasetabellene riktig.

Koden min som treffer Sequelize er som følger:

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();
  };

Ideelt sett vil jeg påstå at define ble kalt på riktig måte, hasMany ble kalt på riktig måte, og sync ble kalt for hver database.

Min testkode er for øyeblikket som følger, selv om den gir en feil om

Kan ikke spionere på authenticate-egenskapen fordi den ikke er en funksjon; udefinert gitt i stedet.

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);
  });
});

Jeg er ikke sikker på om spyOn er den riktige metoden å kalle, eller om jeg kan/hvordan jeg kan bruke jest.mock for å mocke og inspisere kall til Sequelize.

Svar #1

Jeg skal bruke jest.mock(moduleName, factory, options) for å manuelt mocke sequelize-modulen.

Enhetstestløsning:

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);
  });
});

enhetstestresultat:

 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

Relaterte artikler