如何使用Mockito为依赖注入的SpringBoot服务编写单元测试
问题背景
你已有两段核心业务代码:
UploadClass:封装S3客户端逻辑,负责将文件上传到S3存储桶,核心代码如下:
public class UploadClass{ @Override public void upload(){ ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentLength(length); PutObjectResult putObjectResult = this.s3Client.putObject(container, object, data, metadata); } }
MyClassServiceImpl:业务服务类,通过构造器注入UploadClass实例,在process()业务方法中调用上传能力,核心代码如下:
@Service public class MyClassServiceImpl implements MyClassService{ private final UploadClass uploadClass; @Autowired MyClassServiceImpl(final UploadClass uploadClass) { this.uploadClass = uploadClass; } @Override public void process() { // 其他业务逻辑 this.uploadClass.upload(); } }
当前需求是为MyClassServiceImpl的process()方法编写单元测试,要求用Mockito模拟UploadClass实例,已搭好测试类基础结构:
@SpringBootTest public class MyClassServiceTest{ @Test void processTest() { } }
具体实现方案
注意:UploadClass的upload()方法是无返回值的void类型,不需要设置模拟返回值,只需要屏蔽其真实S3上传逻辑、验证方法被正确调用即可。由于MyClassServiceImpl采用构造器注入,有两种常见测试实现方式,按需选择即可。
方式1:纯Mockito单元测试(推荐,执行效率高)
这种方式不需要启动完整Spring容器,测试运行速度快,适合纯业务逻辑验证:
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.verify; // 启用Mockito注解支持 @ExtendWith(MockitoExtension.class) public class MyClassServiceTest { // 生成UploadClass的模拟实例 @Mock private UploadClass mockUploadClass; private MyClassService myClassService; @BeforeEach void setUp() { // 手动通过构造器注入mock对象,初始化被测服务 myClassService = new MyClassServiceImpl(mockUploadClass); } @Test void processTest() { // 对void返回的upload方法打桩:调用时不执行真实上传逻辑 doNothing().when(mockUploadClass).upload(); // 执行被测业务方法 myClassService.process(); // 验证upload方法确实被调用,确认业务逻辑走到上传步骤 verify(mockUploadClass).upload(); // process方法内其他业务逻辑的断言、验证可补充在此处 } }
方式2:基于@SpringBootTest的集成测试写法
如果你需要加载Spring上下文做集成测试,用@MockBean替换容器内的真实UploadClass实例即可:
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.verify; @SpringBootTest public class MyClassServiceTest { // 将Spring容器中真实的UploadClass替换为mock实例,自动注入到依赖它的Bean中 @MockBean private UploadClass mockUploadClass; @Autowired private MyClassService myClassService; @Test void processTest() { doNothing().when(mockUploadClass).upload(); myClassService.process(); verify(mockUploadClass).upload(); } }
补充说明
- void方法不能使用
when().thenReturn()语法打桩,除了示例里的doNothing(),如果要测试异常分支,还可以用doThrow()模拟上传抛出异常的场景:doThrow(new RuntimeException("S3连接失败")).when(mockUploadClass).upload(); - 日常业务逻辑验证优先选第一种纯单元测试写法,不需要加载全量Spring配置,执行速度会快很多。
内容的提问来源于stack exchange,提问作者Nimasha Fernando
相关产品推荐
相关产品推荐

