【问题标题】:sequelize.sync({ force: true }) sometimes fails to set up database correctlysequelize.sync({ force: true }) 有时无法正确设置数据库
【发布时间】:2017-12-19 00:21:40
【问题描述】:

我正在尝试使用 Sequelize 和 PostgreSQL 设置测试夹具。但是,我编写的测试有时会通过,有时会失败。错误范围从SequelizeDatabaseError: type "participants_id_seq" already existsSequelizeUniqueConstraintError: Validation errorSequelizeDatabaseError: relation "participants" does not exist,这让我相信要么我错误地设置了等待,要么我错误地设置了同步。我试过使用 async/await,我也试过用回调设置 Promises,但没有任何运气。

每次测试之前,我都会打电话给sync({ force: true }),就像这样

const { sequelize, participants: Participants } = require('../../models');

const existingUserCredentials = {
  teamName: 'TeamName',
  firstName: 'FirstName',
  lastName: 'LastName',
  email: 'helloworld@helloworld.com',
  password: 'helloworld',
};

const Fixture = async () => {
  try {
    await sequelize.sync({ force: true });
    await Participants.create(existingUserCredentials);
  } catch (err) {
    logger.error(err);
    throw err;
  }
};

module.exports = {
  Fixture
};

然后我在我的测试用例中这样调用它:

describe('POST /login', () => {
  beforeEach(async () => {
    await Fixture();
  });

  it('throws unauthorized when user does not exist', async () => {
    const { body, status } = await request(app)
      .post('/api/login')
      .send({
        email: 'someemail@helloworld.com',
        password: 'hunter123',
      });

    expect(body).toEqual({
      message: messages.INVALID_LOGIN_CREDENTIALS,
    });
    expect(status).toEqual(HttpStatus.UNAUTHORIZED);
  });
});

此测试在某些时间会通过,而在其余时间会失败并出现不同的错误。

我的模型如下所示:

const bcrypt = require('bcryptjs');

module.exports = (sequelize, DataTypes) => {
  const Participant = sequelize.define('participants', {
    teamName: {
      type: DataTypes.STRING,
      allowNull: true,
    },
    firstName: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    lastName: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    email: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    password: {
      type: DataTypes.STRING,
      allowNull: false,
      set(password) {
        const hash = bcrypt.hashSync(password, bcrypt.genSaltSync(10));
        this.setDataValue('password', hash);
      },
    },
  });

  Participant.verifyPassword = (password, hash) =>
    bcrypt.compareSync(password, hash);

  return Participant;
};

我的迁移看起来像这样

module.exports = {
  up: (queryInterface, Sequelize) =>
    queryInterface.createTable('participants', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER,
      },
      teamName: {
        type: Sequelize.STRING,
        allowNull: true,
      },
      firstName: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      lastName: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      email: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      password: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      createdAt: {
        allowNull: false,
        type: 'TIMESTAMP',
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
      },
      updatedAt: {
        allowNull: false,
        type: 'TIMESTAMP',
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
      },
    }),
  down: (queryInterface) => queryInterface.dropTable('participants'),
};

我是否进行了正确设置,以便每次测试都有一个干净的数据库?感谢您的帮助!

【问题讨论】:

    标签: javascript postgresql sequelize.js jestjs


    【解决方案1】:

    更新

    我想通了。事实证明,Jest 并行运行测试用例,因此测试数据库被多个测试用例同时使用。真正的解决方案是通过在测试命令中添加--runInBand 标志来顺序运行测试用例

    // package.json
    {
        ...
        "scripts": {
            ...
            "test": "cross-env NODE_ENV=test jest --runInBand"
        }
        ...
    }
    

    但是,这会减慢运行测试用例的时间。更好的解决方案可能是模拟您的数据库,而不是使用实际的测试数据库。有几个,例如sequelize-mocksequelize-mocking


    所以,我无法用 PostgreSQL 解决这个问题。相反,我将我的 Sequelize 配置切换为使用 SQLite 进行测试,并且它有效。这是我的配置

    module.exports = {
      development: {
        username: process.env.PGUSER,
        password: process.env.PGPASSWORD,
        database: process.env.PGDATABASE,
        host: process.env.PGHOST || '127.0.0.1',
        dialect: 'postgres',
        operatorsAliases: false,
      },
      test: {
        username: process.env.SQLITEUSER,
        password: process.env.SQLITEPASSWORD,
        database: process.env.SQLITEDATABASE,
        host: process.env.PGHOST || '127.0.0.1',
        dialect: 'sqlite',
        operatorsAliases: false,
      },
      production: {
        username: process.env.PGUSER,
        password: process.env.PGPASSWORD,
        database: process.env.PGPRODDATABASE,
        host: process.env.PGHOST || '127.0.0.1',
        dialect: 'postgres',
        operatorsAliases: false,
        logging: false,
      },
    };
    

    我将保留这个问题,因为我真的不认为这是一个好的解决方案

    【讨论】:

      猜你喜欢
      • 2017-12-11
      • 2021-09-15
      • 1970-01-01
      • 2012-06-28
      • 1970-01-01
      • 1970-01-01
      • 2012-06-05
      • 2012-05-19
      相关资源
      最近更新 更多