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

Mockito中@Spy与@InjectMocks使用问题:测试ProjectsService异常

解决Mockito中Service内部方法Mock不生效的问题

问题核心

测试ProjectsService的assignSharedProjects()方法时,需要跳过内部getSharedProjects()的真实调用(避免触发依赖的ProjectsRepository操作),但尝试@Spy或直接when()语法均未生效,反而因真实调用触发RuntimeException(projectsRepository实例不可用)。

原因分析

  1. 直接用@InjectMocks注入的ProjectsService是真实实例,Mockito无法拦截真实对象的方法调用,因此when(projectsService.getSharedProjects(...))不会生效。
  2. 使用@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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 03:23:12