在Android JUnit5/Mockito测试中如何为Spy/Mock对象注入特定整数字段?
解决JUnit5测试中Android隐藏字段注入问题
场景说明
应用中引用的Android类存在一个隐藏字段,真机运行时,因为应用拥有
android.uid.system高权限,该字段始终可访问;但在JUnit5测试环境中,该字段不存在,导致单元测试执行失败。
被测Java应用方法
/** * 被测Java应用中的方法 * * 参数包含一个仅运行时可访问的隐藏整数字段。真机上APK因拥有高权限(android.uid.system)运行正常, * 但JUnit运行时该字段无法访问 * */ static void methodInMyApplication(DataProcessor dataProcessObj){ dataProcessObj.hiddenInteger = 5; // 该字段仅在真机运行时存在 }
Kotlin编写的JUnit5测试类
/** * 用Kotlin编写的JUnit 5测试类 * */ @ExtendWith(MockitoExtension::class) // JUnit5注解 class WifiUnitTests { @Spy private val spyDataProccessor: DataProcessor = DataProcessor() @Test fun testMyJavaMethod() { MyApp.methodInMyApplication(spyDataProccessor) // 此处崩溃,因"hiddenInteger"字段不存在 } }
问题
请问如何在调用应用方法前,手动将该隐藏整数字段注入到Spy或Mock对象中?我已尝试org.junit.platform.commons.util.ReflectionUtils中的setField方法,但该方法不存在,该方法仅在Spring Framework中可用,JUnit Commons中没有。
解决方案
方案1:使用Java原生反射动态添加字段
直接用Java原生反射API给Spy对象动态添加字段并设置访问权限,无需依赖第三方工具类:
@ExtendWith(MockitoExtension::class) class WifiUnitTests { @Spy private val spyDataProccessor: DataProcessor = DataProcessor() @Test fun testMyJavaMethod() { // 动态添加hiddenInteger字段到Spy实例的类中 val field = Field.declareField(spyDataProccessor.javaClass, "hiddenInteger", Int::class.javaPrimitiveType) // 设置字段可访问 field.isAccessible = true // 可选:提前初始化字段值,也可以由被测方法自行设置 field.setInt(spyDataProccessor, 0) // 调用被测方法 MyApp.methodInMyApplication(spyDataProccessor) } }
方案2:创建子类添加字段后Spy
如果DataProcessor允许继承,可以创建一个测试用子类,手动添加字段后再Spy这个子类:
// 自定义测试用子类,添加目标字段 class TestableDataProcessor : DataProcessor() { var hiddenInteger: Int = 0 } @ExtendWith(MockitoExtension::class) class WifiUnitTests { @Spy private val spyDataProccessor: TestableDataProcessor = TestableDataProcessor() @Test fun testMyJavaMethod() { MyApp.methodInMyApplication(spyDataProccessor) // 可验证字段是否被正确设置为5 assertEquals(5, spyDataProccessor.hiddenInteger) } }
内容的提问来源于Stack Exchange,提问作者Oke Uwechue
相关产品推荐
相关产品推荐

