MockK模拟UUID静态类时直接调用randomUUID()出现权限错误的解决方案咨询
你遇到的这个权限错误是Java 9+模块化系统导致的:java.base模块没有将java.util包的私有成员开放给测试所在的未命名模块,而MockK在尝试mockUUID.randomUUID()并返回UUID实例时,需要调用到UUID内部的私有静态方法parse4Nibbles,从而触发了这个访问限制。
下面给你两种可行的解决方案:
方案一:预先构建UUID实例,mockrandomUUID()直接返回实例
这种方式不需要修改VM参数,而是提前准备好合法的UUID实例,让MockK直接返回这些实例,避免触发UUID内部的私有方法访问。
你可以用UUID.fromString()方法创建合法的UUID实例(只要字符串符合UUID格式即可),示例代码如下:
// 预先准备UUID实例列表 val uuidSource = listOf( UUID.fromString("550e8400-e29b-41d4-a716-446655440000"), UUID.fromString("550e8400-e29b-41d4-a716-446655440001"), UUID.fromString("550e8400-e29b-41d4-a716-446655440002") ) @Test fun x1() { mockkStatic(UUID::class) // 直接mock randomUUID()返回预先准备的实例 every { UUID.randomUUID() } returnsMany uuidSource listOf(1, 2, 3).forEach { _ -> println(UUID.randomUUID()) } }
方案二:添加VM参数开放模块访问权限
如果需要动态生成UUID实例而不是硬编码字符串,可以通过添加JVM参数,让java.base模块开放java.util包的私有成员给未命名模块。
Gradle配置方式
在你的build.gradle.kts(或build.gradle)中给测试任务添加JVM参数:
tasks.test { jvmArgs("--add-opens", "java.base/java.util=ALL-UNNAMED") }
IntelliJ运行配置方式
在IntelliJ的测试运行配置中,找到"VM options"栏,添加:
--add-opens java.base/java.util=ALL-UNNAMED
补充说明:为什么链式调用toString()没问题?
你之前测试中every { UUID.randomUUID().toString() } returnsMany uuidSource能正常工作,是因为MockK只拦截了toString()方法的调用,并没有真正mockrandomUUID()返回UUID实例——它相当于在一个"虚拟"的UUID对象上mock了toString()的返回值,不会触发UUID内部的私有方法访问,因此避开了模块化权限限制。
备注:内容来源于stack exchange,提问作者Lopamudra Rath

