简体   繁体   English

maven 中的 Mockito 使用 JPMS 无法访问带有修饰符“私有”的 class 的成员

[英]Mockito in maven using JPMS cannot access a member of class with modifiers "private"

I am migrating a codebase to Java 11 and JPMS / Jigsaw and am having some trouble with mocking.我正在将代码库迁移到 Java 11 和 JPMS / Jigsaw,但在使用 mocking 时遇到了一些问题。

This is the test I am trying to run.这是我要运行的测试。

import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class DbTest {

    @Mock
    private Connection connection;

    @Mock
    private PreparedStatement preparedStatement;

    @Captor
    private ArgumentCaptor<Timestamp> dateCaptor;

    @Test
    public void setTimestamp_instant() throws SQLException {
        Instant inputTime = Instant.parse("2018-03-12T10:25:37.386Z");
        when(connection.prepareStatement(anyString())).thenReturn(preparedStatement);
        PreparedStatement preparedStatement = connection.prepareStatement("UPDATE fakeTable SET time = ? WHERE TRUE");
        RowPack rowPack = new RowPack(preparedStatement, DatabaseType.MYSQL);
        rowPack.setTimestamp(inputTime);
        verify(preparedStatement).setTimestamp(anyInt(), dateCaptor.capture(), Mockito.any(Calendar.class));
    }
}

When running this test in Eclipse it passes but when I run it through maven it fails due to mockito being unable to find some resources using reflection.在 Eclipse 中运行此测试时,它通过了,但是当我通过 maven 运行它时,由于 mockito 无法使用反射找到某些资源,它失败了。

org.mockito.exceptions.base.MockitoException: Problems setting field connection annotated with @org.mockito.Mock(name="", stubOnly=false, extraInterfaces={}, answer=RETURNS_DEFAULTS, serializable=false, lenient=false)
Caused by: java.lang.IllegalAccessException: class org.mockito.internal.util.reflection.ReflectionMemberAccessor cannot access a member of class foo.bar.DbTest (in module foo.bar) with modifiers "private"

I am using Surefire 3.0.0-M5, junit 5.7.0 and mockito 3.5.10.我使用的是 Surefire 3.0.0-M5、junit 5.7.0 和 mockito 3.5.10。

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>

Needless to say this worked well in maven before switching to modularising with JPMS.不用说,在切换到使用 JPMS 进行模块化之前,这在 maven 中运行良好。

I have read Testing in the modular world and tried the junit-platform-maven-plugin as a replacement for surefire but ran into similar problems with mockito.我已经阅读了模块化世界中的测试,并尝试使用 junit-platform-maven-plugin 作为 surefire 的替代品,但遇到了与 mockito 类似的问题。

Help would be greatly appreciated.帮助将不胜感激。

TL;DR — You need to configure the Surefire Plugin to pass the --add-opens option to java when it runs your test… TL;DR — 您需要配置 Surefire 插件,以便在运行测试时将--add-opens选项传递给java ……

--add-opens --添加打开

If you have to allow code on the class path to do deep reflection to access nonpublic members, then use the --add-opens runtime option.如果必须允许类路径上的代码进行深度反射以访问非公共成员,请使用--add-opens运行时选项。

Some libraries do deep reflection, meaning setAccessible(true) , so they can access all members, including private ones.一些库会进行深度反射,即setAccessible(true) ,因此它们可以访问所有成员,包括私有成员。 You can grant this access using the --add-opens option on the java command line…您可以使用java命令行上的--add-opens选项授予此访问权限...


Although I wasn't able to reproduce 100% verbatim the error message in your question, I was able to produce one that was pretty much the same.虽然我无法 100% 逐字重现您问题中的错误消息,但我能够生成一个几乎相同的错误消息。 It was similar enough to yours, that I'm confident that the root cause ( and the solution ) of both mine and yours is the same.它与您的非常相似,我相信我和您的根本原因(和解决方案)是相同的。

In this demo that you can download and build , I resolved the error I got with…在这个你可以下载和构建的演示中,我解决了我遇到的错误......

…
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M5</version>
    <configuration>
        …
        <argLine>add-opens foo.bar/foo.bar=ALL-UNNAMED</argLine>
        …
    </configuration>
</plugin>
…

Download and build the demo .下载并构建演示 Feel free to modify it however you see fit.随意修改它,但你认为合适。

Another solution is to configure the maven-surefire-plugin with <useModulePath>false</useModulePath> , which will stop enforcing modular access control.另一种解决方案是使用<useModulePath>false</useModulePath>配置 maven- <useModulePath>false</useModulePath> -plugin,这将停止强制执行模块化访问控制。

Caution: This will make your tests run on the classpath.注意:这将使您的测试在类路径上运行。 Usually, you want tests to run in as similar an environment as possible to that at runtime.通常,您希望测试在与运行时尽可能相似的环境中运行。

My solution was to place an own module-info.java inside the test sources ( src/test/java in Maven) specifying open (See Allowing runtime-only access to all packages in a module ) for the test module with the following contents:我的解决方案是在测试源(Maven 中的src/test/java中放置一个自己的module-info.java ,为测试模块指定open (请参阅允许仅运行时访问模块中的所有包),其中包含以下内容:

// "open" seems to be the magic word: it opens up for reflective access
// the same module name like for the main module must be used, so the main module has also the name "com.foo.bar"
open module com.foo.bar {
// I use still juni4
    requires junit;
// require Mockito here
    requires org.mockito;
// very important, Mockito needs it
    requires net.bytebuddy;
// add here your stuff
    requires org.bouncycastle.provider;
}

I had a similar problem.我有一个类似的问题。 I am using Junit and Mockito on a Java 11 jpms project and wanted to run my tests using maven.我在 Java 11 jpms 项目上使用 Junit 和 Mockito 并想使用 maven 运行我的测试。

To build upon deduper's great answer, I added:为了建立 deduper 的好答案,我补充说:

<configuration>
    <argLine>--add-opens foo.bar/foo.bar=ALL-UNNAMED</argLine>
</configuration>

on my surefire configuration.在我的 surefire 配置上。

Notice the 2 prefixed dashes -- , without them add-opens was parsed as a class and throws an Error.请注意 2 个带前缀的破折号-- ,如果没有它们,add-opens 将被解析为 class 并引发错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 春季:FasterXML无法使用修饰符private访问类的成员 - Spring : FasterXML cannot access a member of class with modifiers private java.lang.IllegalAccessException:. 无法使用修饰符“private static”访问类 CrossOrigin 的成员 - java.lang.IllegalAccessException:.cannot access the member of class CrossOrigin with modifiers "private static" jsonobject IllegalAccessException无法使用修饰符“private”访问类java.util.HashMap的成员 - jsonobject IllegalAccessException can not access a member of class java.util.HashMap with modifiers “private” 是否需要在私有内部类中声明访问修饰符 - Is there a need to declare access modifiers in a private inner class 无法使用修饰符“public”访问类java.nio.DirectByteBuffer(在模块java.base中)的成员 - cannot access a member of class java.nio.DirectByteBuffer (in module java.base) with modifiers “public” Spring Access修饰符私有 - Spring access modifiers private 使用Mockito访问JUnit中经过测试的类中的私有字段 - Access private field in tested class in JUnit with Mockito 为什么类或接口不能接收私有或受保护的访问修饰符? - Why can't a class or an interface receive private or protected access modifiers? 在Java中的私有静态嵌套类中访问修饰符 - Access modifiers inside a private static nested class in Java Javafx WebView无法访问带有修饰符“ public”的类的成员。 - Javafx WebView can not access a member of class … with modifiers “public”
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM