NestJS中AnswerService测试失败求助:'should be defined'不通过
NestJS AnswerService单元测试失败问题解决
问题描述
测试基于NestJS的测验API时,对基础AnswerService的单元测试中,should be defined用例失败。刚接触Jest,了解GraphQL Resolver的Mock概念,但不知道如何正确配置测试所需的Providers。
服务代码
import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Answer } from './entities/answer.entity'; import { DeepPartial } from 'typeorm'; import { CreateAnswerInput } from './dto/create-answer.input'; @Injectable() export class AnswerService { constructor( @InjectRepository(Answer) private readonly answerRepository: Repository<Answer>, ){} async createAnswer(question_id: number, createAnswerInput: CreateAnswerInput): Promise <Answer>{ const { answer_content, is_correct, priority } = createAnswerInput; const answer: DeepPartial<Answer> = { question: {id: question_id}, answer_content, is_correct, priority, }; const savedAnswer = await this.answerRepository.save(answer); return savedAnswer; } async getAnswers(questionId: number): Promise <Answer[]>{ return this.answerRepository.find({where: { question: { id: questionId } }}) } }
原测试代码
import { Test, TestingModule } from '@nestjs/testing'; import { getRepositoryToken } from '@nestjs/typeorm'; import { Any, DataSource, Repository } from 'typeorm'; import { AnswerService } from './answer.service'; import { Answer } from './entities/answer.entity'; describe('AnswerService', () => { let service: AnswerService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [AnswerService, Answer] }).compile(); service = module.get<AnswerService>(AnswerService) }); it('should be defined', () => { expect(service).toBeDefined(); }); describe('createAnswer', () => { it('should create and return new answer', async () => { const newAnswer = await service.createAnswer(1, { answer_content: "content", priority: 1, is_correct: null }) expect(newAnswer).toEqual({ id: expect.any(Number), answer_content: "content", priority: 1, is_correct: null, question: {id: 1} }) }); }); });
错误原因
原测试代码的核心问题是错误配置了Providers:
- AnswerService依赖的是
Repository<Answer>(通过@InjectRepository(Answer)注入),但测试模块里直接把Answer实体加入providers,这无法满足依赖需求。Nest无法自动将实体解析为Repository,导致服务无法实例化,最终should be defined用例失败。
修复步骤
要正确配置测试模块,需要模拟TypeORM的Repository,具体操作:
- 使用
getRepositoryToken(Answer)获取Repository的注入令牌,这是Nest识别TypeORM Repository依赖的关键。 - 提供一个Mock Repository对象,包含服务中用到的
save、find等方法(用Jest的jest.fn()模拟)。 - 在测试用例中,为Mock方法设置返回值,确保逻辑测试能正常执行。
完整修复后的测试代码
import { Test, TestingModule } from '@nestjs/testing'; import { getRepositoryToken } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { AnswerService } from './answer.service'; import { Answer } from './entities/answer.entity'; // 定义Mock Repository的类型 type MockRepository<T = any> = Partial<Record<keyof Repository<T>, jest.Mock>>; describe('AnswerService', () => { let service: AnswerService; let answerRepository: MockRepository<Answer>; beforeEach(async () => { // 创建Mock Repository const mockAnswerRepo = { save: jest.fn(), find: jest.fn(), }; const module: TestingModule = await Test.createTestingModule({ providers: [ AnswerService, // 配置Mock Repository作为依赖 { provide: getRepositoryToken(Answer), useValue: mockAnswerRepo, }, ], }).compile(); service = module.get<AnswerService>(AnswerService); answerRepository = module.get(getRepositoryToken(Answer)); }); it('should be defined', () => { expect(service).toBeDefined(); }); describe('createAnswer', () => { it('should create and return new answer', async () => { // 设置Mock save方法的返回值 const mockSavedAnswer = { id: 1, answer_content: "content", priority: 1, is_correct: null, question: {id: 1} }; answerRepository.save.mockResolvedValue(mockSavedAnswer); const result = await service.createAnswer(1, { answer_content: "content", priority: 1, is_correct: null }); expect(result).toEqual(mockSavedAnswer); // 验证save方法是否被正确调用 expect(answerRepository.save).toHaveBeenCalledWith({ question: {id: 1}, answer_content: "content", priority: 1, is_correct: null, }); }); }); describe('getAnswers', () => { it('should return answers for a given question', async () => { const mockAnswers = [ {id: 1, answer_content: "Answer 1", question: {id: 1}}, {id: 2, answer_content: "Answer 2", question: {id: 1}}, ]; answerRepository.find.mockResolvedValue(mockAnswers); const result = await service.getAnswers(1); expect(result).toEqual(mockAnswers); expect(answerRepository.find).toHaveBeenCalledWith({ where: { question: { id: 1 } } }); }); }); });
关键说明
getRepositoryToken(Answer):Nest用来标识Repository<Answer>依赖的令牌,必须用这个来绑定Mock对象。- Mock Repository的方法:根据服务中实际调用的方法(如
save、find)来模拟,不需要实现所有Repository方法。 mockResolvedValue:用于模拟异步方法的返回值,对应服务中的await调用。
内容的提问来源于stack exchange,提问作者Adrian Cielniak
相关产品推荐
相关产品推荐

