如何在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
相关产品推荐
相关产品推荐

