You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,具体操作:

  1. 使用getRepositoryToken(Answer)获取Repository的注入令牌,这是Nest识别TypeORM Repository依赖的关键。
  2. 提供一个Mock Repository对象,包含服务中用到的save、find等方法(用Jest的jest.fn()模拟)。
  3. 在测试用例中,为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 11:07:00