Sequelize的createdAt/updatedAt毫秒被舍为000,单元测试比对失败如何解决?
问题根源
这个差异是因为你使用的数据库(如MySQL 5.6及更早版本、默认配置的SQLite)的DATETIME类型默认不支持存储毫秒值:createJob返回的是Sequelize在内存中生成的实例,时间戳带完整毫秒精度;数据写入数据库时毫秒部分被直接截断,后续查询返回的时间戳毫秒位统一为000,因此全量比对时会报错。
最优解决方案
根据你的业务需求二选一即可:
方案1:单元测试侧统一抹平毫秒差异(优先推荐,改造成本最低)
如果业务不需要毫秒级时间精度,仅需要单元测试正常通过,不需要改动生产代码和表结构,只需在比对前统一处理两个对象的时间戳,移除毫秒部分即可。
示例代码:
// 通用工具函数:移除时间的毫秒部分 const trimTimeMillis = (jobObj) => { const processed = {...jobObj}; ['createdAt', 'updatedAt'].forEach(timeField => { if (processed[timeField] instanceof Date) { processed[timeField] = new Date(Math.floor(processed[timeField].getTime() / 1000) * 1000); } }); return processed; } // 比对前先处理两个对象 assert.deepStrictEqual(trimTimeMillis(actual), trimTimeMillis(expected));
如果使用Jest等测试框架,也可以直接配置忽略毫秒位的校验:
// 校验除时间外所有字段完全一致 expect(actual).toEqual(expect.objectContaining({ ...expected, createdAt: expect.any(Date), updatedAt: expect.any(Date) })); // 单独校验时间的秒级部分一致 expect(Math.floor(actual.createdAt.getTime()/1000)).toBe(Math.floor(expected.createdAt.getTime()/1000)); expect(Math.floor(actual.updatedAt.getTime()/1000)).toBe(Math.floor(expected.updatedAt.getTime()/1000));
方案2:修改数据库和Sequelize配置支持毫秒存储
如果业务本身需要保留毫秒级时间精度,可修改表字段类型支持毫秒存储,同时调整Sequelize模型配置:
以MySQL 5.7+为例,其支持DATETIME(3)类型存储3位毫秒值,在模型定义时配置如下即可:
const { DataTypes } = require('sequelize'); const Job = sequelize.define('Job', { // 其他自定义字段 }, { timestamps: true, createdAt: { type: DataTypes.DATE(3) }, updatedAt: { type: DataTypes.DATE(3) } });
配置后数据库会存储完整毫秒值,查询返回的时间戳和创建时返回的实例时间戳完全一致,直接全量比对不会报错。
内容的提问来源于stack exchange,提问作者NickW
相关产品推荐
相关产品推荐

