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

仅用Mockito/JUnit如何Mock javax.mail.Transport类?

解决方案

一、仅用Mockito/JUnit实现:重构代码解耦依赖

Mockito默认不支持Mock静态方法,所以要不用PowerMock,必须先重构MailSender,把对Transport的静态调用改成可注入的依赖:

1. 重构MailSender类

把静态方法改为实例方法,封装邮件发送逻辑为可替换的接口:

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;

public class MailSender {
    // 定义接口封装发送逻辑
    public interface MailTransport {
        void send(MimeMessage message) throws MessagingException;
    }

    private final MailTransport transport;

    // 生产环境使用默认实现
    public MailSender() {
        this.transport = javax.mail.Transport::send;
    }

    // 测试环境注入Mock实现
    public MailSender(MailTransport transport) {
        this.transport = transport;
    }

    // 改为实例方法
    public boolean sendMail(String fromAddress, String content, String toAddress) {
        try {
            // 原有构造MimeMessage的逻辑示例
            MimeMessage mimeMessage = new MimeMessage(Session.getDefaultInstance(new Properties()));
            mimeMessage.setFrom(new InternetAddress(fromAddress));
            mimeMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(toAddress));
            mimeMessage.setText(content);

            transport.send(mimeMessage);
            return true;
        } catch (MessagingException e) {
            e.printStackTrace();
            return false;
        }
    }
}

2. 编写Mockito测试

现在可以正常Mock自定义的MailTransport接口,完全避免实际发邮件:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.any;

@ExtendWith(MockitoExtension.class)
class MailSenderTest {

    @Mock
    private MailSender.MailTransport mockTransport;

    @InjectMocks
    private MailSender mailSender;

    @Test
    void sendMail_shouldReturnTrueWhenSuccess() throws MessagingException {
        // Mock发送成功的场景
        doNothing().when(mockTransport).send(any(MimeMessage.class));

        boolean result = mailSender.sendMail("me@gmail.com", "hi", "you@gmail.com");
        assertEquals(true, result);
    }

    @Test
    void sendMail_shouldReturnFalseWhenFailure() throws MessagingException {
        // Mock发送失败的场景
        doThrow(new MessagingException("发送失败")).when(mockTransport).send(any(MimeMessage.class));

        boolean result = mailSender.sendMail("me@gmail.com", "hi", "you@gmail.com");
        assertEquals(false, result);
    }
}

二、不重构代码的方案:使用PowerMock(不推荐)

如果必须保留原有静态方法和直接调用Transport.send的逻辑,才需要用PowerMock来Mock静态方法:

1. 添加PowerMock依赖(Maven示例)

<dependencies>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4</artifactId>
        <version>2.0.9</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-api-mockito2</artifactId>
        <version>2.0.9</version>
        <scope>test</scope>
    </dependency>
</dependencies>

2. 编写PowerMock测试代码

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import javax.mail.Transport;
import javax.mail.internet.MimeMessage;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.any;

@RunWith(PowerMockRunner.class)
@PrepareForTest(Transport.class) // 指定要Mock的静态类
class MailSenderTest {

    @Test
    void sendMail_success() throws Exception {
        // Mock静态方法Transport.send
        PowerMockito.mockStatic(Transport.class);
        PowerMockito.doNothing().when(Transport.class);
        Transport.send(any(MimeMessage.class));

        boolean result = MailSender.sendMail("me@gmail.com", "hi", "you@gmail.com");
        assertEquals(true, result);
    }
}

原有测试代码的问题总结

  1. @Mock和@InjectMocks注解使用错误:应该给测试类MailSender加@InjectMocks,给依赖对象加@Mock
  2. Mockito无法直接MockTransport的静态方法,这是核心限制
  3. 静态方法sendMail不应通过实例调用,且Mockito无法Mock静态方法内部的静态调用
  4. 字符串转义错误:"you@gmail.com"写成了""you@gmail.com""

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 12:25:14