如何用JUnit/Mockito测试含数据库加载静态码表的Java类?
无需/低依赖注入的Codes类测试方案
方案1:通过反射直接修改静态CODES集合
利用Java反射API直接替换静态CODES集合的内容,完全不需要修改业务代码,跳过数据库加载逻辑。
示例测试代码:
import org.junit.jupiter.api.BeforeEach; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; class CodesTest { @BeforeEach void setUp() throws NoSuchFieldException, IllegalAccessException { // 获取静态CODES字段 Field codesField = Codes.class.getDeclaredField("CODES"); // 取消访问权限检查 codesField.setAccessible(true); // 构造测试用码表数据 Map<String, String> testCodes = new HashMap<>(); testCodes.put("001", "测试状态1"); testCodes.put("002", "测试状态2"); // 替换静态字段值 codesField.set(null, testCodes); } @org.junit.jupiter.api.Test void getCodeStr_ShouldReturnCorrectValue() { assert Codes.getCodeStr("001").equals("测试状态1"); assert Codes.getCodeStr("002").equals("测试状态2"); } }
- 优点:零业务代码侵入,无需额外依赖,仅用JUnit原生能力即可实现。
- 缺点:反射代码对字段名强依赖,若业务类中
CODES字段更名,测试代码需同步修改。
方案2:添加测试专用的静态初始化方法
在Codes类中新增一个包级私有或测试可见的静态方法,用于手动注入测试数据,生产环境不会调用该方法。
原Codes类修改(仅新增测试方法):
public class Codes { private static Map<String, String> CODES; public static void init() { // 原数据库加载逻辑 } public static String getCodeStr(String code) { return CODES.get(code); } // 测试专用方法,包级私有,仅同包测试类可调用 static void setTestCodes(Map<String, String> testCodes) { CODES = testCodes; } }
测试类代码:
import org.junit.jupiter.api.BeforeEach; import java.util.HashMap; import java.util.Map; class CodesTest { @BeforeEach void setUp() { Map<String, String> testCodes = new HashMap<>(); testCodes.put("001", "测试状态1"); Codes.setTestCodes(testCodes); } @org.junit.jupiter.api.Test void getCodeStr_ShouldReturnCorrectValue() { assert Codes.getCodeStr("001").equals("测试状态1"); } }
- 优点:代码直观易维护,比反射写法简洁;仅需对业务类做极小改动,不影响生产逻辑。
- 缺点:业务类中引入了测试相关代码,虽无功能影响,但属于非业务代码侵入。
方案3:用PowerMock静态Mock跳过数据库加载
若能接受引入少量扩展依赖,可使用PowerMock(Mockito的扩展)mock静态方法和字段,直接跳过数据库加载逻辑并注入测试数据。
首先添加Maven测试依赖:
<dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>2.0.9</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>2.0.9</version> <scope>test</scope> </dependency>
测试类代码:
import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import java.util.HashMap; import java.util.Map; @RunWith(PowerMockRunner.class) @PrepareForTest(Codes.class) public class CodesTest { @Test void getCodeStr_ShouldReturnCorrectValue() { // 构造测试数据 Map<String, String> testCodes = new HashMap<>(); testCodes.put("001", "测试状态1"); // 静态mock Codes类,替换CODES字段 PowerMockito.field(Codes.class, "CODES").set(null, testCodes); // 验证查询结果 assert Codes.getCodeStr("001").equals("测试状态1"); } }
- 优点:可直接mock掉
init方法的执行,避免数据库连接尝试;代码比反射更简洁。 - 缺点:需要引入PowerMock依赖,有一定学习成本;JUnit5需使用对应版本的PowerMock适配包。
内容的提问来源于stack exchange,提问作者BigMac66
相关产品推荐
相关产品推荐

