Nest.js 中的模拟 bcrypt 模块模块
Mock bcrypt module module in Nest.js
我正在尝试模拟 bcrypt 哈希方法实现,但出现以下错误:
Error: thrown: "Exceeded timeout of 5000 ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
我尝试将超时增加到 30000。我还尝试模拟整个 bcrypt 模块,例如 jest.mock('bcrypt')。
我是测试新手,可能存在一些逻辑错误或不良做法。如果您指出它们,我将不胜感激。
我的代码:
import { UserService } from '../user.service';
import { Test, TestingModule } from '@nestjs/testing';
import { Repository } from 'typeorm';
import { getRepositoryToken } from '@nestjs/typeorm';
import * as bcrypt from 'bcrypt';
import { UserEntity } from '../user.entity';
import { UserRepository } from '../user.repository';
import { CreateUserDto } from '../dto/create-user.dto';
import { userStub } from './stubs/user.stub';
describe('UserService', () => {
let userService: UserService;
let userRepository: Repository<UserEntity>;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
UserService,
{
provide: getRepositoryToken(UserRepository),
useClass: Repository,
},
],
}).compile();
userService = module.get<UserService>(UserService);
userRepository = module.get<Repository<UserEntity>>(
getRepositoryToken(UserRepository),
);
});
it('should define UserService', () => {
expect(userService).toBeDefined();
});
it('should define userRepository', () => {
expect(userRepository).toBeDefined();
});
describe('createUser method', () => {
it('has called with valid data', async () => {
const createUserDto: CreateUserDto = {
email: userStub().email,
firstName: userStub().firstName,
lastName: userStub().lastName,
password: userStub().password,
};
const user: UserEntity = userStub();
const spiedBcryptHashMethod = jest
.spyOn(bcrypt, 'hash')
.mockImplementation(() => Promise.resolve(''));
const spiedRepositoryCreateMethod = jest
.spyOn(userRepository, 'create')
.mockReturnValue(user);
const spiedRepositorySaveMethod = jest
.spyOn(userRepository, 'save')
.mockResolvedValue(user);
const createUserResult = await userService.createUser(createUserDto);
expect(spiedBcryptHashMethod).toHaveBeenCalled();
expect(spiedRepositoryCreateMethod).toHaveBeenCalled();
expect(spiedRepositorySaveMethod).toHaveBeenCalledWith(user);
expect(createUserResult).toEqual(user);
});
});
});
此处出现错误:
const spiedBcryptHashMethod = jest
.spyOn(bcrypt, 'hash')
.mockImplementation(() => Promise.resolve(''));
我的用户服务代码:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import * as bcrypt from 'bcrypt';
import { UserRepository } from './user.repository';
import { CreateUserDto } from './dto/create-user.dto';
import { UserEntity } from './user.entity';
@Injectable()
export class UserService {
constructor(
@InjectRepository(UserRepository) private userRepository: UserRepository,
) {}
public async createUser(createUserDto: CreateUserDto): Promise<UserEntity> {
return await this.userRepository.save(
this.userRepository.create({
...createUserDto,
password: await new Promise((resolve, reject) => {
bcrypt.hash(createUserDto.password, 10, (err, encrypted) => {
if (err) {
reject(err);
}
resolve(encrypted);
});
}).then((onFilled: string) => onFilled),
}),
);
}
}
好的,关于您的服务代码,有很多话要说...
您遇到问题的直接问题是因为您将 bcrypt 的 hash
方法模拟为 return 一个承诺,但是 使用 方法因为它 return 是一个回调。 如果你想继续使用回调和 promises 方法,你需要做类似
的事情
jest.spyOn(bcrypt, 'hash').mockImplementation((pass, salt, cb) => cb(null, ''))
这与 Promise.resolve('')
基本相同。
但是我不建议这样做。 Bcrypt 内置了 promise 支持,所以不用用你自己的 promise 包装回调,你可以只做 await bcrypt.hash(pass, salt)
然后你会得到散列密码,然后你的 Promise.resolve('')
将按照你的意图工作也。我也没有看到 then((onFullfilled: string) => onFullfilled)
的必要性,但是如果您无论如何都删除自定义承诺,那将消失。
一般来说,尽量坚持使用单一的异步方法。所有回调(不再建议)、所有承诺(更好)或所有 async/await(现在几乎是标准)。
我正在尝试模拟 bcrypt 哈希方法实现,但出现以下错误:
Error: thrown: "Exceeded timeout of 5000 ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
我尝试将超时增加到 30000。我还尝试模拟整个 bcrypt 模块,例如 jest.mock('bcrypt')。 我是测试新手,可能存在一些逻辑错误或不良做法。如果您指出它们,我将不胜感激。
我的代码:
import { UserService } from '../user.service';
import { Test, TestingModule } from '@nestjs/testing';
import { Repository } from 'typeorm';
import { getRepositoryToken } from '@nestjs/typeorm';
import * as bcrypt from 'bcrypt';
import { UserEntity } from '../user.entity';
import { UserRepository } from '../user.repository';
import { CreateUserDto } from '../dto/create-user.dto';
import { userStub } from './stubs/user.stub';
describe('UserService', () => {
let userService: UserService;
let userRepository: Repository<UserEntity>;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
UserService,
{
provide: getRepositoryToken(UserRepository),
useClass: Repository,
},
],
}).compile();
userService = module.get<UserService>(UserService);
userRepository = module.get<Repository<UserEntity>>(
getRepositoryToken(UserRepository),
);
});
it('should define UserService', () => {
expect(userService).toBeDefined();
});
it('should define userRepository', () => {
expect(userRepository).toBeDefined();
});
describe('createUser method', () => {
it('has called with valid data', async () => {
const createUserDto: CreateUserDto = {
email: userStub().email,
firstName: userStub().firstName,
lastName: userStub().lastName,
password: userStub().password,
};
const user: UserEntity = userStub();
const spiedBcryptHashMethod = jest
.spyOn(bcrypt, 'hash')
.mockImplementation(() => Promise.resolve(''));
const spiedRepositoryCreateMethod = jest
.spyOn(userRepository, 'create')
.mockReturnValue(user);
const spiedRepositorySaveMethod = jest
.spyOn(userRepository, 'save')
.mockResolvedValue(user);
const createUserResult = await userService.createUser(createUserDto);
expect(spiedBcryptHashMethod).toHaveBeenCalled();
expect(spiedRepositoryCreateMethod).toHaveBeenCalled();
expect(spiedRepositorySaveMethod).toHaveBeenCalledWith(user);
expect(createUserResult).toEqual(user);
});
});
});
此处出现错误:
const spiedBcryptHashMethod = jest
.spyOn(bcrypt, 'hash')
.mockImplementation(() => Promise.resolve(''));
我的用户服务代码:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import * as bcrypt from 'bcrypt';
import { UserRepository } from './user.repository';
import { CreateUserDto } from './dto/create-user.dto';
import { UserEntity } from './user.entity';
@Injectable()
export class UserService {
constructor(
@InjectRepository(UserRepository) private userRepository: UserRepository,
) {}
public async createUser(createUserDto: CreateUserDto): Promise<UserEntity> {
return await this.userRepository.save(
this.userRepository.create({
...createUserDto,
password: await new Promise((resolve, reject) => {
bcrypt.hash(createUserDto.password, 10, (err, encrypted) => {
if (err) {
reject(err);
}
resolve(encrypted);
});
}).then((onFilled: string) => onFilled),
}),
);
}
}
好的,关于您的服务代码,有很多话要说...
您遇到问题的直接问题是因为您将 bcrypt 的 hash
方法模拟为 return 一个承诺,但是 使用 方法因为它 return 是一个回调。 如果你想继续使用回调和 promises 方法,你需要做类似
jest.spyOn(bcrypt, 'hash').mockImplementation((pass, salt, cb) => cb(null, ''))
这与 Promise.resolve('')
基本相同。
但是我不建议这样做。 Bcrypt 内置了 promise 支持,所以不用用你自己的 promise 包装回调,你可以只做 await bcrypt.hash(pass, salt)
然后你会得到散列密码,然后你的 Promise.resolve('')
将按照你的意图工作也。我也没有看到 then((onFullfilled: string) => onFullfilled)
的必要性,但是如果您无论如何都删除自定义承诺,那将消失。
一般来说,尽量坚持使用单一的异步方法。所有回调(不再建议)、所有承诺(更好)或所有 async/await(现在几乎是标准)。