我正在为沙盒项目编写单元测试,以测试 NestJS 中的一些内容。我遇到了一个问题,在单元测试中模拟时,采用注入服务 (
authService
) 的类显示为未定义。然而,当我使用提供者令牌注入它时,该服务似乎被正确地模拟并且不会显示为未定义。
我想这个问题是因为我没有正确制作模拟模块,因为这两种方法都可以在实践中找到(在单元测试之外)。只有在测试期间,我只能使用提供者令牌进行模拟,否则
authService
中的 AuthImplementation
显示为未定义。
这是我的模块 -
auth.module.ts
@Module({
imports: [DatabaseModule],
controllers: [AuthController],
providers: [
{
provide: 'UserRepository',
useFactory: (databaseAdapterService: DatabaseAdapterService) =>
databaseAdapterService.getUserRepository(),
inject: [DatabaseAdapterService],
},
{
provide: AuthService,
useFactory: (userRepository: UserRepository) => {
return new AuthService(userRepository);
},
inject: ['UserRepository'],
},
{
provide: AuthImplementation,
useFactory: (authService: IAuthService) =>
new AuthImplementation(authService),
inject: [AuthService],
},
]
})
AuthImplementation 类如下 -
auth.implementation.ts
import { Inject } from '@nestjs/common';
import { User } from 'src/domain/entities/user.entity';
import { AUTH_SERVICE, IAuthService } from 'src/domain/ports/auth-service.interface';
export class AuthImplementation {
constructor(@Inject(AUTH_SERVICE) private readonly authService: IAuthService) { }
// This approach, without the provider token, fails the unit tests because
// authService shows up as undefined when mocked
// constructor(private readonly authService: IAuthService) { }
async register(username: string, password: string): Promise<User> {
return this.authService.register(username, password);
}
async login(username: string, password: string): Promise<User | null> {
return this.authService.login(username, password);
}
}
仅当使用提供者令牌定义
provide
的 mockAuthService
字段时才有效的单元测试如下所示 - auth.implementation.spec.ts
describe('AuthImplementation', () => {
let authImplementation: AuthImplementation;
let mockAuthService: jest.Mocked<IAuthService>;
beforeEach(async () => {
mockAuthService = {
register: jest.fn(),
login: jest.fn(),
};
const module: TestingModule = await Test.createTestingModule({
providers: [
AuthImplementation,
{
// NOTE: This approach does not work
//provide: AuthService,
// NOTE: This works just fine
provide: AUTH_SERVICE,
useValue: mockAuthService,
},
],
}).compile();
authImplementation = module.get<AuthImplementation>(AuthImplementation);
});
describe('register', () => {
it('should register a user and return the user object', async () => {
const username = 'testuser';
const password = 'testpass';
const mockUser = new User(new ObjectId(), username, password);
mockAuthService.register.mockResolvedValue(mockUser);
const result = await authImplementation.register(username, password);
expect(mockAuthService.register).toHaveBeenCalledWith(username, password);
expect(result).toBe(mockUser);
});
});
所以我的问题是,有没有办法直接引用测试模块中的AuthService,而不是必须定义一个提供者令牌(例如
export const AUTH_SERVICE = Symbol('AUTH_SERVICE');
)并在注入身份验证服务时使用它?为什么我可以逃脱:
provide: AUTH_SERVICE,
但不是
provide: AuthService,
在记录时在 AuthImplementation 中产生未定义的结果
authService
?
你解决这个问题了吗?我也有同样的问题