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

如何使用Mockito模拟EntityManager测试getAllSkeletons方法?

用Mockito测试getAllSkeletons方法的分步指南

刚好我之前也处理过类似的JPA仓库方法测试,结合你给出的代码,给你一步步拆解怎么用Mockito完成测试,同时兼顾正常流程和异常场景:

1. 先准备必要的依赖

确保你的项目里引入了Mockito核心库和JUnit(这里以JUnit 5为例),如果是Maven项目,在pom.xml里添加这些依赖:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.11.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>4.11.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

2. 处理EntityManager的获取问题

你的getEntityManager()方法是调用静态方法EntityController.getEntityManager()获取实例,这里有两种测试方案:

方案A:重构代码(推荐)

更符合依赖注入原则的方式是把EntityManager作为类的依赖注入,这样测试时直接mock即可,不需要处理静态调用:

private final EntityManager entityManager;

// 通过构造函数注入EntityManager
public YourRepositoryClass(EntityManager entityManager) {
    this.entityManager = entityManager;
}

// 简化原有的getEntityManager方法
protected EntityManager getEntityManager() {
    return entityManager;
}

方案B:用Mockito静态mock(不重构的情况)

如果暂时不想调整代码,Mockito 3.4+支持静态方法mock,用来模拟EntityController.getEntityManager()的返回:

try (MockedStatic<EntityController> mockedStatic = Mockito.mockStatic(EntityController.class)) {
    mockedStatic.when(EntityController::getEntityManager).thenReturn(mockEntityManager);
    // 在这里执行测试逻辑
}

3. 完整测试代码示例

假设你的类名叫ExamSkeletonRepository,下面是覆盖正常场景和异常场景的测试代码:

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.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class ExamSkeletonRepositoryTest {

    @Mock
    private EntityManager entityManager;

    @Mock
    private TypedQuery<ExamSkeleton> typedQuery;

    @InjectMocks
    private ExamSkeletonRepository repository; // 替换成你的实际类名

    @Test
    void getAllSkeletons_WhenDataExists_ReturnsSkeletonList() {
        // 1. 准备测试数据
        ExamSkeleton skeleton1 = new ExamSkeleton(1L, "exam1.pdf", "Math", true);
        ExamSkeleton skeleton2 = new ExamSkeleton(2L, "exam2.pdf", "English", false);
        List<ExamSkeleton> expectedSkeletons = Arrays.asList(skeleton1, skeleton2);

        // 2. 模拟JPA调用链
        when(entityManager.createQuery(anyString(), eq(ExamSkeleton.class))).thenReturn(typedQuery);
        when(typedQuery.getResultList()).thenReturn(expectedSkeletons);

        // 如果用方案B,需要包裹静态mock:
        // try (MockedStatic<EntityController> mockedStatic = mockStatic(EntityController.class)) {
        //     mockedStatic.when(EntityController::getEntityManager).thenReturn(entityManager);
        //     // 执行下面的调用和断言
        // }

        // 3. 调用待测试方法
        List<ExamSkeleton> actualSkeletons = repository.getAllSkeletons();

        // 4. 验证结果与调用行为
        assertEquals(expectedSkeletons.size(), actualSkeletons.size());
        assertEquals(expectedSkeletons, actualSkeletons);
        verify(entityManager, times(1)).createQuery(anyString(), eq(ExamSkeleton.class));
        verify(typedQuery, times(1)).getResultList();
    }

    @Test
    void getAllSkeletons_WhenQueryThrowsException_ReturnsEmptyList() {
        // 1. 模拟异常抛出
        when(entityManager.createQuery(anyString(), eq(ExamSkeleton.class)))
                .thenThrow(new IllegalArgumentException("Invalid JPA query"));

        // 如果用方案B,同样需要包裹静态mock

        // 2. 调用待测试方法
        List<ExamSkeleton> result = repository.getAllSkeletons();

        // 3. 验证结果
        assertTrue(result.isEmpty());
        assertEquals(Collections.emptyList(), result);
        // 若要验证日志输出,需将LOGGER改为类成员变量并@Mock,然后添加:
        // verify(logger, times(1)).error(any(IllegalArgumentException.class));
    }
}

额外提示

  • 若你的LOGGER是静态字段,测试日志调用需要用PowerMock或Mockito静态mock;更推荐用SLF4J的@Slf4j注解生成非静态LOGGER,方便直接mock验证。
  • 测试要覆盖所有代码分支:正常返回数据、异常返回空列表,确保每个路径都被验证到。
  • 优先选择方案A重构代码,不仅简化测试,也符合SOLID设计原则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:47:08