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

如何为EmailService的bookingEmail方法编写JUnit测试(含两种Runner及参数捕获)

EmailService的JUnit测试实现方案

针对EmailService类的bookingEmail方法,以下是对应三个需求的具体实现:

1. 使用@RunWith(SpringRunner.class)实现测试

SpringRunner是SpringJUnit4ClassRunner的别名,用于在JUnit 4中集成Spring上下文,适合需要加载部分Spring组件的测试场景。

修正后的测试代码

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {EmailService.class, TestConfig.class}) // 引入测试配置类
public class EmailServiceTest {
    private ScheduledTimeList testScheduledTimeList;
    private static final String TEST_APP_EMAIL = "test@example.com";

    @Autowired
    @Qualifier("emailConfigBean")
    private FreeMarkerConfigurationFactoryBean emailConfig;

    @MockBean // 替换Spring上下文中的HttpEmailService为Mock实例
    private HttpEmailService httpEmailService;

    @Autowired
    private EmailService emailService;

    @Before
    public void setup() {
        // 构造测试用的ScheduledTimeList(根据实际类结构补充属性)
        testScheduledTimeList = new ScheduledTimeList();
    }

    @Test
    public void bookingEmail_Success() throws Exception {
        // 执行测试方法
        String result = emailService.bookingEmail(testScheduledTimeList, TEST_APP_EMAIL);

        // 验证返回结果
        Assert.assertEquals("success", result);
        // 验证邮件发送方法被调用一次
        Mockito.verify(httpEmailService, Mockito.times(1)).sendEmail(Mockito.any(EmailRequest.class));
    }
}

关键说明

  • @SpringBootTest指定加载EmailService和测试配置类,确保FreeMarker配置和业务类被正确初始化。
  • @MockBean自动替换Spring上下文里的HttpEmailService为Mock对象,避免触发真实邮件发送。
  • 修正原有测试代码错误:无需手动实例化EmailService,Spring会自动完成注入。

2. 使用@RunWith(MockitoJUnitRunner.class)实现测试

完全可以用MockitoJUnitRunner实现,这种方式无需加载Spring上下文,纯依赖Mockito完成Mock和注入,测试速度更快,适合单元测试场景。

测试代码实现

@RunWith(MockitoJUnitRunner.class)
public class EmailServiceMockitoTest {
    private ScheduledTimeList testScheduledTimeList;
    private static final String TEST_APP_EMAIL = "test@example.com";

    @Mock // Mock FreeMarker配置类
    private FreeMarkerConfigurationFactoryBean emailConfig;

    @Mock // Mock邮件发送服务
    private HttpEmailService httpEmailService;

    @InjectMocks // 自动将Mock对象注入到EmailService实例
    private EmailService emailService;

    @Before
    public void setup() throws Exception {
        // 构造测试用的ScheduledTimeList
        testScheduledTimeList = new ScheduledTimeList();

        // Mock FreeMarker相关逻辑,避免真实模板加载
        Configuration mockConfig = Mockito.mock(Configuration.class);
        Template mockTemplate = Mockito.mock(Template.class);
        Mockito.when(emailConfig.getObject()).thenReturn(mockConfig);
        Mockito.when(mockConfig.getTemplate("emailTemplateNames.ftl")).thenReturn(mockTemplate);
        // Mock模板渲染结果
        Mockito.when(FreeMarkerTemplateUtils.processTemplateIntoString(mockTemplate, Mockito.anyMap()))
                .thenReturn("<html>Test Email Content</html>");
    }

    @Test
    public void bookingEmail_Success() throws Exception {
        String result = emailService.bookingEmail(testScheduledTimeList, TEST_APP_EMAIL);

        Assert.assertEquals("success", result);
        Mockito.verify(httpEmailService, Mockito.times(1)).sendEmail(Mockito.any(EmailRequest.class));
    }
}

关键说明

  • @RunWith(MockitoJUnitRunner.class)启用Mockito的JUnit集成,自动初始化@Mock和@InjectMocks标注的对象。
  • @InjectMocks会自动将所有@Mock依赖注入到EmailService,无需手动构造实例。
  • 若需验证真实模板渲染逻辑,可去掉FreeMarker相关Mock,手动初始化FreeMarkerConfigurationFactoryBean并指定测试模板路径。

3. 捕获方法调用的参数

使用Mockito的ArgumentCaptor可以捕获方法调用时传入的参数,用于验证参数的正确性。

示例代码(以SpringRunner测试为例)

@Test
public void bookingEmail_VerifyEmailRequest() throws Exception {
    // 创建参数捕获器
    ArgumentCaptor<EmailRequest> emailRequestCaptor = ArgumentCaptor.forClass(EmailRequest.class);

    // 执行测试方法
    emailService.bookingEmail(testScheduledTimeList, TEST_APP_EMAIL);

    // 捕获sendEmail方法的参数
    Mockito.verify(httpEmailService).sendEmail(emailRequestCaptor.capture());
    EmailRequest capturedRequest = emailRequestCaptor.getValue();

    // 验证参数属性
    Assert.assertEquals(TEST_APP_EMAIL, capturedRequest.getTo());
    Assert.assertEquals("Subject", capturedRequest.getSubject());
    Assert.assertNotNull(capturedRequest.getHtmlContent());
    // 验证模板变量是否正确渲染(使用真实模板时)
    Assert.assertTrue(capturedRequest.getHtmlContent().contains(TEST_APP_EMAIL));
}

关键说明

  • ArgumentCaptor.forClass(EmailRequest.class)创建对应类型的参数捕获器。
  • Mockito.verify(httpEmailService).sendEmail(emailRequestCaptor.capture())触发参数捕获,需确保方法已被调用。
  • 通过capturedRequest可获取实际传入的参数,验证其属性是否符合业务预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 05:43:18