问题
I am migrating a codebase to Java 11 and JPMS / Jigsaw and am having some trouble with 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.
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.
<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.
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.
Help would be greatly appreciated.
回答1:
TL;DR — You need to configure the Surefire Plugin to pass the --add-opens option to java
when it runs your test…
--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.Some libraries do deep reflection, meaning
setAccessible(true)
, so they can access all members, including private ones. You can grant this access using the--add-opens
option on thejava
command line…
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. 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.
来源:https://stackoverflow.com/questions/64120676/mockito-in-maven-using-jpms-cannot-access-a-member-of-class-with-modifiers-priv