如何在Jest单元测试中适配bcrypt加密以测试FindAll()方法
调整NestJS用户查询测试用例(适配bcrypt加密密码)
针对密码加密导致测试断言失败的问题,提供三种实用调整方案:
方案1:Mock Prisma服务,返回预设哈希密码
单元测试应隔离外部依赖,直接mock Prisma的查询方法,返回带有预先生成哈希密码的用户数据,避免依赖实际加密逻辑或数据库。
示例代码:
// 在测试模块初始化时mock PrismaService const module: TestingModule = await Test.createTestingModule({ providers: [ UsersService, { provide: PrismaService, useValue: { users: { findMany: jest.fn().mockResolvedValue([ { username: 'user1', name: 'User One', password: '$2b$10$Z8HxQaoxeQ7V7kLzW5sKqOvXrTtY.uB9eFgHjKlMnOpQrStUvWxYz', // 预先生成的bcrypt哈希值 email: 'user1@test.com', tasks: [], }, { username: 'user2', name: 'User Two', password: '$2b$10$AbCdEfGhIjKlMnOpQrStUvWxYzZaBcDeFgHiJkLmNoPqRsTuVwX', email: 'user2@test.com', tasks: [], }, ]), }, }, }, ], }).compile(); const service = module.get<UsersService>(UsersService); const prisma = module.get<PrismaService>(PrismaService); // 测试用例 describe('findAll', () => { it('should return all users with hashed passwords', async () => { const result = await service.findAll(); expect(prisma.users.findMany).toHaveBeenCalled(); // 可直接匹配预设哈希数据,或只验证非密码字段 expect(result.map(u => ({ username: u.username, name: u.name, email: u.email }))) .toEqual(usersMany.map(u => ({ username: u.username, name: u.name, email: u.email }))); }); });
方案2:集成测试场景:预先生成加密密码存入测试库
如果是需要连接测试数据库的集成测试,可在测试前用bcrypt加密明文密码,插入数据库后再断言返回的哈希值有效性。
示例代码:
import * as bcrypt from 'bcrypt'; describe('findAll', () => { beforeEach(async () => { // 加密明文密码 const hashedPwd1 = await bcrypt.hash('123', 10); const hashedPwd2 = await bcrypt.hash('456', 10); // 插入测试数据 await prisma.users.createMany({ data: [ { ...usersMany[0], password: hashedPwd1 }, { ...usersMany[1], password: hashedPwd2 }, ], }); }); afterEach(async () => { // 清理测试数据 await prisma.users.deleteMany(); }); it('should return users with valid hashed passwords', async () => { const result = await service.findAll(); // 验证哈希密码可匹配原明文 expect(await bcrypt.compare('123', result[0].password)).toBe(true); expect(await bcrypt.compare('456', result[1].password)).toBe(true); // 验证其他字段正确性 expect(result[0].username).toBe(usersMany[0].username); expect(result[1].email).toBe(usersMany[1].email); }); });
方案3:断言时忽略密码字段
如果测试重点是验证用户列表的基本信息,无需关注密码具体值,可直接排除密码字段后对比。
示例代码:
describe('findAll', () => { it('should return all users (ignore password field)', async () => { const result = await service.findAll(); // 移除密码字段后对比 const cleanResult = result.map(({ password, ...rest }) => rest); const cleanExpected = usersMany.map(({ password, ...rest }) => rest); expect(cleanResult).toEqual(cleanExpected); }); });
内容的提问来源于stack exchange,提问作者AnonymousGeese
相关产品推荐
相关产品推荐

