Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mock(SecureRandom.class) and mock(Random.class) fails #2560

Closed
Kurru opened this issue Feb 4, 2022 · 6 comments
Closed

mock(SecureRandom.class) and mock(Random.class) fails #2560

Kurru opened this issue Feb 4, 2022 · 6 comments

Comments

@Kurru
Copy link

Kurru commented Feb 4, 2022

Trying to mock SecureRandom or Random throws exception.

mock(SecureRandom.class);

Throws exception:

Mockito cannot mock this class: class java.security.SecureRandom.

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


Underlying exception : java.lang.IllegalStateException: Cannot access annotation property public abstract java.lang.String jdk.internal.util.random.RandomSupport$RandomGeneratorProperties.name()
org.mockito.exceptions.base.MockitoException: 
Mockito cannot mock this class: class java.security.SecureRandom.

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

However, if I disable the annotation mocking, this code completes successfully.

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

Random and SecureRandom seem relatively common, perhaps this can be handled more gracefully? Or perhaps the error message can highlight that this may be an annotation only problem and thus can be worked around?

@Kurru
Copy link
Author

Kurru commented Feb 5, 2022

This has been resolved in some projects by adding an extra arg to the jvm

--add-exports=java.base/jdk.internal.util.random=ALL-UNNAMED

Source

@cushon
Copy link
Contributor

cushon commented Feb 23, 2022

I think the annotations on Random were added as part of https://bugs.openjdk.java.net/browse/JDK-8248862

--add-exports= isn't ideal because it requires setting the flag on every affected test, or setting it for an entire project.

Making the withSettings().withoutAnnotations() behaviour more automatic for SecureRandom and Random seems appealing, because it avoids having to configure --add-exports=, and because I don't think the annotations are likely to matter here.

@TimvdLippe
Copy link
Contributor

Does this also happen if you use the inline mockmaker? (Assuming you are using the default subclass mockmaker)

Please see https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#0.2 for instructions on how to do so.

@cushon
Copy link
Contributor

cushon commented Feb 23, 2022

Does this also happen if you use the inline mockmaker?

It does not.

Is that a barrier to working around this in the default subclass mockmaker?

java -cp .:objenesis-3.2.jar:asm-9.2.jar:byte-buddy-1.12.8.jar:hamcrest-2.2.jar:junit-4.13.jar:mockito-core-4.3.1.jar:byte-buddy-agent-1.12.8.jar \
 org.junit.runner.JUnitCore com.test.FooTest
...
Underlying exception : java.lang.IllegalStateException: Cannot access annotation property public abstract java.lang.String jdk.internal.util.random.RandomSupport$RandomGeneratorProperties.name()
        at com.test.FooTest.test(FooTest.java:14)
        ... 32 trimmed
java -cp .:objenesis-3.2.jar:asm-9.2.jar:byte-buddy-1.12.8.jar:hamcrest-2.2.jar:junit-4.13.jar:mockito-inline-4.3.1.jar:mockito-core-4.3.1.jar:byte-buddy-agent-1.12.8.jar \
org.junit.runner.JUnitCore com.test.FooTest
JUnit version 4.13
...
OK (1 test)

@TimvdLippe
Copy link
Contributor

We had a short discussion about this in #1728 In general, the subclass mockmaker will be more and more difficult to work correctly on newer versions of the JDk, for which the inline mockmaker will work as expected. This is primarily because the subclass mockmaker has to access internal types that are slowly but surely locked off in the JDK. The inline mockmaker does not have the same limitations.

Therefore, we are considering switching the default mockmaker to the inline mockmaker to make Mockito future-proof. Especially in the last few months, the amount of JDK 16-17+ related issues have significantly ramped up. Therefore, I think we have to consider doing so sooner rather than later.

@TimvdLippe
Copy link
Contributor

Closing this per #2589

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants