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

如何在NestJS测试代码中创建Nodemailer模拟对象/工厂?

NestJS测试时模拟Nodemailer避免发送真实邮件

方案一:模拟依赖的EmailService

因为你的UserService依赖EmailService发送验证邮件,测试时直接替换EmailService为模拟对象即可,无需真实调用nodemailer:

修改users.service.spec.ts中的测试模块配置:

import { Test } from '@nestjs/testing';
import { UsersService } from './users.service';
import { EmailService } from '../email/email.service';

describe('UsersService', () => {
  let usersService: UsersService;
  let emailService: EmailService;

  beforeEach(async () => {
    const moduleRef = await Test.createTestingModule({
      providers: [
        UsersService,
        // 模拟EmailService
        {
          provide: EmailService,
          useValue: {
            sendVerificationEmail: jest.fn().mockResolvedValue(true),
          },
        },
        // 记得同时模拟其他依赖(比如UsersRepository)
      ],
    }).compile();

    usersService = moduleRef.get<UsersService>(UsersService);
    emailService = moduleRef.get<EmailService>(EmailService);
  });

  it('创建用户时应调用邮件发送方法', async () => {
    const testUser = { email: 'test@example.com', password: '123456' };
    await usersService.createUser(testUser);
    
    // 验证邮件方法是否被调用
    expect(emailService.sendVerificationEmail).toHaveBeenCalledWith(
      testUser.email,
      expect.any(String) // 验证链接参数
    );
  });
});

方案二:直接模拟Nodemailer模块

如果需要测试EmailService本身,但不想发送真实邮件,可以直接mock nodemailer的createTransport和sendMail方法:

在email.service.spec.ts中添加:

import { Test } from '@nestjs/testing';
import { EmailService } from './email.service';
import * as nodemailer from 'nodemailer';

// 模拟nodemailer整个模块
jest.mock('nodemailer', () => {
  const mockSendMail = jest.fn().mockResolvedValue({ messageId: 'test-mail-id' });
  return {
    createTransport: jest.fn().mockReturnValue({
      sendMail: mockSendMail,
    }),
  };
});

describe('EmailService', () => {
  let emailService: EmailService;

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

    emailService = moduleRef.get<EmailService>(EmailService);
  });

  it('发送验证邮件时应调用nodemailer的sendMail', async () => {
    await emailService.sendVerificationEmail('test@example.com', 'test-token');
    
    const mockTransporter = nodemailer.createTransport.mock.results[0].value;
    expect(mockTransporter.sendMail).toHaveBeenCalledWith(expect.objectContaining({
      to: 'test@example.com',
      subject: expect.any(String),
    }));
  });
});

额外注意事项

  • 移除测试文件中加载开发环境.env的代码(比如dotenv.config({ path: path.resolve('src/config/env/.development.env') })),避免测试时使用真实邮箱配置触发真实邮件发送。
  • 确保测试环境使用独立的配置,或者通过模拟完全绕过真实的邮件发送逻辑。

内容的提问来源于stack exchange,提问作者ReactScript

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 13:55:37