mysql 擦除模式中的所有表- sequelize nodejs

zujrkrfu  于 2023-05-16  发布在  Mysql
关注(0)|答案(2)|浏览(121)

要使用sequelize as ORM在mysql数据库上执行单元测试,我需要在每个测试开始运行时刷新数据库。实际上,我写了一个这样的解决方案:

beforeEach(() => {
   table1.destroy({ where: {} })
   table2.destroy({ where: {} })
   table3.destroy({ where: {} })
})

但每次创建表时,我都必须添加另一条指令。我将实现一条指令来执行整个模式的完全擦除
类似于:

beforeEach(() => db.clean())
djp7away

djp7away1#

sequelize.truncate({ cascade: true, restartIdentity: true })

记录在:https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#instance-method-truncate这将截断所有表,这似乎最接近您想要的:
截断通过序列化模型定义的所有表。这是通过在每个模型上调用Model.truncate()来完成的。
对于option参数:
除了truncate之外,传递给Model.destroy的选项
并行测试可以使用以下提到的技术之一进行处理:Willhttps://sqa.stackexchange.com/questions/16854/designing-database-reliant-tests-for-parallel-execution/47244#47244的mocking suggestion也解决了并行问题,因此也值得研究一下。
{truncate: cascade}在涉及外键时是必需的,否则PostgreSQL 13.4会抱怨:

cannot truncate a table referenced in a foreign key constraint

{truncate: cascade}使其运行TRUNCATE "Mytable" CASCADE而不仅仅是TRUNCATE "MyTable",相关:

{restartIdentity: true}还可以通过重置主键计数器来帮助提高测试的可重复性:How to reset autoIncrement primary key with sequelize?但请注意,它在SQLite上是坏的:https://github.com/sequelize/sequelize/issues/13286
最小可运行示例:

const assert = require('assert');
const { Sequelize, DataTypes } = require('sequelize');

const sequelize = new Sequelize({
  dialect: 'sqlite',
  storage: 'db.sqlite',
});
const IntegerNames = sequelize.define(
  'IntegerNames', {
  value: { type: DataTypes.INTEGER, allowNull: false },
  name: { type: DataTypes.STRING, },
});
const IntegerNames2 = sequelize.define(
  'IntegerNames2', {
  value: { type: DataTypes.INTEGER, allowNull: false },
  name: { type: DataTypes.STRING, },
});

(async () => {
// Create and populate databases.
await IntegerNames.sync({force: true})
await IntegerNames.create({value: 2, name: 'two'});
await IntegerNames.create({value: 3, name: 'three'});
await IntegerNames2.sync({force: true})
await IntegerNames2.create({value: 4, name: 'four'});
await IntegerNames2.create({value: 5, name: 'five'});

// Check that they were populated.
assert((await IntegerNames.findAll()).length === 2);
assert((await IntegerNames2.findAll()).length === 2);

// Truncate them and check that they are empty.
await sequelize.truncate({ cascade: true, restartIdentity: true });
assert((await IntegerNames.findAll()).length === 0);
assert((await IntegerNames2.findAll()).length === 0);

// Cleanup.
await sequelize.close();
})();

当我们运行此命令时,Sequelize会记录以下两行数据库代码:

Executing (default): DELETE FROM `IntegerNames2s`
Executing (default): DELETE FROM `IntegerNames`

这似乎是TRUNCATE语句的版本,根据:https://sqlite.org/lang_delete.html#the_truncate_optimization
在6.5.1,Node v14.16.0上测试。

另一种测试方法:SQLite内存数据库

对于在SQLite上进行测试,这是一个很好的方法,它可以确保每次测试都是完全干净的,您甚至不必担心截断或创建唯一的数据库名称

new Sequelize({
  dialect: 'sqlite',
  storage: ':memory:',
})
eblbsuwk

eblbsuwk2#

进行 * 单元测试 * 时,请勿接触数据库。

如果您正在测试与sequelize对话的业务逻辑,请创建要sequelize的接口的模拟,并将其注入到正在测试的单元中。然后,您可以针对对模拟接口的方法的调用做出Assert或期望。如果没有测试环境的更多细节,就不可能提供比这更具体的指导,但是您可以研究sequelize-mocking包来促进这一点。
如果你正在测试sequelize实际上是在和你的数据库对话,那么你所做的不仅仅是单元测试,我认为你会想要一种带外的方式来初始化和管理环境,但我也要指出,sequelize已经有了一整套测试。

相关问题