NestJS单元测试与E2E测试

最近在使用NestJS进行开发,想请教大家关于测试的问题:

  1. 单元测试和E2E测试在NestJS中具体有哪些区别?各自的适用场景是什么?
  2. 在编写单元测试时,如何正确mock依赖的服务和模块?有没有推荐的最佳实践?
  3. E2E测试中,数据库和外部API的mock有什么好的解决方案?测试数据该如何管理?
  4. 有没有提高测试运行效率的技巧?比如如何避免重复初始化或减少测试耗时?
  5. 大家在实际项目中是如何平衡单元测试和E2E测试覆盖率的?

希望有经验的朋友能分享一些实战心得,谢谢!

3 回复

在NestJS中,单元测试和E2E(端到端)测试是确保代码质量的重要手段。

单元测试:主要关注的是单一函数或模块的行为。在NestJS中,你可以使用Jest来编写单元测试。例如,对服务层的业务逻辑进行测试时,可以模拟依赖的服务或仓库,只测试当前模块的功能是否正确。示例代码如下:

describe('AuthService', () => {
  let service: AuthService;

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [AuthService],
    }).compile();

    service = module.get<AuthService>(AuthService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });
});

E2E测试:用于验证整个应用的流程是否正常工作,通常涉及多个模块间的交互。使用@nestjs/testing提供的Test模块搭建测试环境,并通过Supertest库发起HTTP请求来模拟客户端行为。例如:

describe('/cats (e2e)', () => {
  let app: INestApplication;

  beforeEach(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  it('/ (GET)', () => {
    return request(app.getHttpServer())
      .get('/')
      .expect(200)
      .expect('Hello World!');
  });

  afterEach(async () => {
    await app.close();
  });
});

单元测试适合快速反馈,而E2E测试则能保证系统整体功能的完整性。两者结合能有效提升代码质量。


在NestJS中,单元测试和E2E测试是两种重要的测试方式。

单元测试主要针对单个模块、服务或控制器的独立功能进行验证。使用Jest作为测试框架,你可以通过Mock技术模拟依赖。例如,对于一个服务方法,你可以单独测试它的逻辑是否正确,而不需要实际调用数据库或其他服务。通常,你会创建一个测试文件,比如auth.service.spec.ts,然后使用describeit来定义测试套件和测试用例。例如:

import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from './auth.service';

describe('AuthService', () => {
  let service: AuthService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [AuthService],
    }).compile();

    service = module.get<AuthService>(AuthService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });
});

E2E测试则侧重于整个应用的功能集成测试,通常用来验证API接口的行为是否符合预期。这类测试会启动整个应用,并向其发送HTTP请求以检查响应。你需要在test目录下创建一个main.e2e-spec.ts文件,使用supertest库来发起请求:

import { Test, TestingModule } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from '../src/app.module';
import { INestApplication } from '@nestjs/common';

describe('AppController (e2e)', () => {
  let app: INestApplication;

  beforeAll(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  it('/ (GET)', () => {
    return request(app.getHttpServer())
      .get('/')
      .expect(200)
      .expect('Hello World!');
  });

  afterAll(async () => {
    await app.close();
  });
});

单元测试确保代码内部逻辑正确,而E2E测试保证各个模块协同工作无误。两者结合能有效提升代码质量。

NestJS提供了完善的测试支持,主要分为单元测试和E2E测试两类:

  1. 单元测试(Unit Testing)
  • 测试单个类/方法/函数
  • 使用Jest作为默认测试框架
  • 常用工具:@nestjs/testing包中的Test
  • 典型场景:服务层、控制器、管道等独立测试

示例(服务测试):

import { Test } from '@nestjs/testing';
import { CatsService } from './cats.service';

describe('CatsService', () => {
  let service: CatsService;

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [CatsService],
    }).compile();

    service = module.get<CatsService>(CatsService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });
});
  1. E2E测试(End-to-End Testing)
  • 测试整个应用流程
  • 模拟真实HTTP请求
  • 使用supertest处理HTTP请求
  • 测试整个模块的集成情况

示例:

import * as request from 'supertest';
import { Test } from '@nestjs/testing';
import { AppModule } from '../src/app.module';

describe('AppController (e2e)', () => {
  let app;

  beforeEach(async () => {
    const moduleFixture = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  it('/ (GET)', () => {
    return request(app.getHttpServer())
      .get('/')
      .expect(200)
      .expect('Hello World!');
  });
});

最佳实践:

  1. 单元测试应占测试主要部分
  2. E2E测试覆盖关键业务流程
  3. 使用jest.mock()模拟外部依赖
  4. 测试覆盖率目标至少70%

两者结合使用可确保应用质量,单元测试快速反馈,E2E测试验证整体行为。

回到顶部