Mockito中@Spy与@InjectMocks使用问题:测试ProjectsService异常
解决Mockito中Service内部方法Mock不生效的问题
问题核心
测试ProjectsService的assignSharedProjects()方法时,需要跳过内部getSharedProjects()的真实调用(避免触发依赖的ProjectsRepository操作),但尝试@Spy或直接when()语法均未生效,反而因真实调用触发RuntimeException(projectsRepository实例不可用)。
原因分析
- 直接用
@InjectMocks注入的ProjectsService是真实实例,Mockito无法拦截真实对象的方法调用,因此when(projectsService.getSharedProjects(...))不会生效。 - 使用
@Spy时,默认会执行真实方法;若用when(...)语法stub,会先调用一次真实方法,进而触发ProjectsRepository的调用导致异常。
解决方案
方案一:使用@Spy + doReturn/doThrow跳过真实方法调用
通过@Spy创建ProjectsService的代理对象,结合doReturn()直接返回模拟结果(不会触发真实方法执行),同时用@InjectMocks注入ProjectsRepository依赖。
业务类示例
@Service public class ProjectsService { private final ProjectsRepository projectsRepository; public ProjectsService(ProjectsRepository projectsRepository) { this.projectsRepository = projectsRepository; } public String assignSharedProjects(String userId) { List<SharedProject> sharedProjects = getSharedProjects(userId); int totalPercentage = sharedProjects.stream() .mapToInt(SharedProject::getPercentage) .sum(); if (totalPercentage > 100) { return "Total Shared Percentage Exceeds 100"; } return "Success"; } // 用protected修饰,方便测试时stub protected List<SharedProject> getSharedProjects(String userId) { return projectsRepository.findSharedProjectsByUserId(userId); } }
测试类示例
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import java.util.List; import static org.mockito.Mockito.doReturn; import static org.junit.jupiter.api.Assertions.assertEquals; @ExtendWith(MockitoExtension.class) public class ProjectsServiceTest { @Mock private ProjectsRepository projectsRepository; @Spy @InjectMocks private ProjectsService projectsService; @Test void assignSharedProjects_WhenTotalExceeds100_ReturnsErrorMessage() { // 构造总和超过100的模拟数据 List<SharedProject> mockProjects = List.of( new SharedProject("proj1", 60), new SharedProject("proj2", 50) ); // 跳过真实方法调用,直接返回模拟数据 doReturn(mockProjects).when(projectsService).getSharedProjects("testUserId"); // 执行测试方法 String result = projectsService.assignSharedProjects("testUserId"); // 断言结果符合预期 assertEquals("Total Shared Percentage Exceeds 100", result); } }
方案二:重构代码,抽离内部逻辑到独立组件
将getSharedProjects()的逻辑抽离为单独的服务类(如SharedProjectHelper),这样可以直接mock该组件,无需处理内部方法的拦截问题,更符合单一职责原则。
重构后的业务类
// 抽离的辅助类 @Service public class SharedProjectHelper { private final ProjectsRepository projectsRepository; public SharedProjectHelper(ProjectsRepository projectsRepository) { this.projectsRepository = projectsRepository; } public List<SharedProject> getSharedProjects(String userId) { return projectsRepository.findSharedProjectsByUserId(userId); } } // 原Service类 @Service public class ProjectsService { private final SharedProjectHelper sharedProjectHelper; public ProjectsService(SharedProjectHelper sharedProjectHelper) { this.sharedProjectHelper = sharedProjectHelper; } public String assignSharedProjects(String userId) { List<SharedProject> sharedProjects = sharedProjectHelper.getSharedProjects(userId); int totalPercentage = sharedProjects.stream() .mapToInt(SharedProject::getPercentage) .sum(); if (totalPercentage > 100) { return "Total Shared Percentage Exceeds 100"; } return "Success"; } }
重构后的测试类
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 java.util.List; import static org.mockito.Mockito.when; import static org.junit.jupiter.api.Assertions.assertEquals; @ExtendWith(MockitoExtension.class) public class ProjectsServiceTest { @Mock private SharedProjectHelper sharedProjectHelper; @InjectMocks private ProjectsService projectsService; @Test void assignSharedProjects_WhenTotalExceeds100_ReturnsErrorMessage() { List<SharedProject> mockProjects = List.of( new SharedProject("proj1", 60), new SharedProject("proj2", 50) ); when(sharedProjectHelper.getSharedProjects("testUserId")).thenReturn(mockProjects); String result = projectsService.assignSharedProjects("testUserId"); assertEquals("Total Shared Percentage Exceeds 100", result); } }
内容的提问来源于stack exchange,提问作者saif barakat
相关产品推荐
相关产品推荐

