Spring Boot中使用Mockito如何Mock Service类内的本地方法
同Service类内部方法Mock实现方案
核心原理
你当前的测试代码使用@InjectMocks注入的是普通的MyServiceImpl实例,调用内部方法时会直接执行真实逻辑,无法单独Mock指定方法。我们可以使用Mockito的**Spy(间谍对象)**实现部分Mock:在真实对象的基础上,仅自定义Mock指定的内部方法,其余方法仍走真实逻辑,刚好适配你测试getSomething、仅Mock同类doSomething的需求。
方案一:纯Mockito单元测试(不启动Spring上下文)
这是单元测试优先推荐的方案,执行速度快,不需要依赖Spring环境。
实现步骤
- 将测试类中原来的
@InjectMocks注解替换为@Spy,Spy会自动注入你声明的@Mock依赖 - 使用
doReturn语法定义内部方法的Mock返回值(不要用when().thenReturn,会触发真实方法执行)
完整测试代码
// JUnit5 写法,JUnit4 替换为 @RunWith(MockitoJUnitRunner.class) @ExtendWith(MockitoExtension.class) public class MyServiceImplTest { @Mock SomeOtherService otherService; // 替换@InjectMocks为@Spy,生成部分Mock的实例 @Spy MyServiceImpl myServiceImpl; @Test public void testGetSomething() { // 1. 构造测试数据 Integer testId = 10; Integer mockSomethingId = 20; Something mockS = new Something(); mockS.setId(mockSomethingId); List<Something> mockReturnList = new ArrayList<>(); // 可按需给mockReturnList添加测试用的自定义元素 // 2. Mock外部依赖的方法 when(otherService.getOfSomething(testId)).thenReturn(mockS); // 3. Mock同类内部的doSomething方法,必须用doReturn避免触发真实调用 doReturn(mockReturnList).when(myServiceImpl).doSomething(mockSomethingId); // 4. 执行待测试的getSomething方法 List<Something> result = myServiceImpl.getSomething(testId); // 5. 断言结果+验证调用 assertEquals(mockReturnList, result); verify(otherService, times(1)).getOfSomething(testId); verify(myServiceImpl, times(1)).doSomething(mockSomethingId); } }
方案二:SpringBoot集成测试场景
如果你的测试需要启动Spring上下文,可以直接使用SpringBoot提供的@SpyBean注解,直接对容器中的Bean做Spy处理:
完整测试代码
@SpringBootTest public class MyServiceImplSpringTest { @MockBean SomeOtherService otherService; // 直接注入Spy处理后的Service实例 @SpyBean MyService myService; @Test public void testGetSomething() { // 测试逻辑和纯Mockito方案完全一致 Integer testId = 10; Integer mockSomethingId = 20; Something mockS = new Something(); mockS.setId(mockSomethingId); List<Something> mockReturnList = new ArrayList<>(); when(otherService.getOfSomething(testId)).thenReturn(mockS); doReturn(mockReturnList).when(myService).doSomething(mockSomethingId); List<Something> result = myService.getSomething(testId); // 断言和验证逻辑同上 } }
常见注意事项
- 禁止使用
when(myServiceImpl.doSomething(anyInt())).thenReturn(xxx)的写法对Spy对象的方法做Mock,该写法会先真实执行一次doSomething方法,可能产生意外的逻辑执行或报错。 - 不建议Mock私有内部方法,如果doSomething是私有方法,优先调整代码结构拆分逻辑,实在需要Mock私有方法可以引入PowerMock实现。
- 如果MyServiceImpl是final类、或者doSomething是final方法,普通Mockito不支持Mock,同样需要引入PowerMock处理,或者调整代码去掉final修饰。
内容的提问来源于stack exchange,提问作者Arpith S
相关产品推荐
相关产品推荐

