mockito 在Java 17中不能模拟随机

dkqlctbz  于 2022-11-08  发布在  Java
关注(0)|答案(4)|浏览(278)

尝试将我的项目从Java 11更新到Java 17,在特定测试中从Mockito得到了一个意外的错误。

mock(java.util.Random.class);

掷回

Feb 04, 2022 3:07:01 PM com.google.inject.internal.MessageProcessor visit
INFO: An exception was caught and reported. Message: java.lang.IllegalAccessException: class 
    net.bytebuddy.description.annotation.AnnotationDescription$ForLoadedAnnotation cannot access interface
    jdk.internal.util.random.RandomSupport$RandomGeneratorProperties (in module java.base) 
    because module java.base does not export jdk.internal.util.random to unnamed module @2f54a33d
org.mockito.exceptions.base.MockitoException: 
Mockito cannot mock this class: class java.util.Random.

Mockito can only mock non-private & non-final classes.
If you're not sure why you're getting this error, please report to the mailing list.

Java               : 17
JVM vendor name    : Oracle Corporation
JVM vendor version : 17.0.2+8-86
JVM name           : OpenJDK 64-Bit Server VM
JVM version        : 17.0.2+8-86
JVM info           : mixed mode, sharing
OS name            : Mac OS X
OS version         : 12.1

不知道为什么Mockito在这个测试中失败。

bxfogqkk

bxfogqkk1#

这里的问题是mockito(通过ByteBuddy)试图在运行时(通过反射)使用一个不可访问的类型。从Java 9开始,不是所有的模块都是可访问的,除非你显式地导出/打开它们。
由于这是一个运行时问题,您可以添加--add-opens作为JVM arg/CLI选项,以使此类型可访问。
根据此处的Oracle指南,--add-opens执行以下操作。
如果您必须允许类路径上的代码执行深度反射以访问非公共成员,则使用--add-opens运行时选项。
如果您也想汇出编译时期可用的内部型别,可以使用--add-exports
解决您的具体问题;请使用以下命令。
--add-opens java.base/jdk.internal.util.random=ALL-UNNAMED .
ALL-UNNAMED表示,指定的软件包在整个代码库中可用。
但是,嘲笑不属于你的类型并不是一个好的做法。也许,如果有其他选择的话,你可以简化这一点。

unhi4e5o

unhi4e5o2#

此特定问题也可通过以下方法解决:

mock(SecureRandom.class, withSettings().withoutAnnotations())
wgeznvg7

wgeznvg73#

升级mokito到4.4.0它工作

zmeyuzjn

zmeyuzjn4#

需要模仿Random表明你的代码没有被写成可测试的。

interface RandomSource {
        /**
         * Return a random number that matches the criteria you need
         */
        int nextNumber();
    }

    @Bean
    class DefaultRandomSource implements RandomSource {
        private final Random r = new Random();
        public int nextNumber() {
            return r.nextInt(2);
        }
    }

    @Bean
    class ClassToTest {
        private final RandomSource randomSource;

        @Autowired
        public ClassToTest(RandomSource randomSource) {
            this.randomSource = randomSource;
        }

        public String doSomething() {
            return randomSource.nextNumber() == 0 ? "Foo" : "Bar";
        }
    }

    @Test
    void testDoSomething() {
        RandomSource r = mock(RandomSource.class);
        when(r.nextNumber()).thenReturn(0);
        ClassToTest classToTest = new ClassToTest(r);
        assertEquals("Foo", classToTest.doSomething());
    }

相关问题