[英]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 thejava
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.