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

Cannot mock this class: class java.io.InputStream with Java 13 #1827

Closed
adamretter opened this issue Nov 24, 2019 · 6 comments
Closed

Cannot mock this class: class java.io.InputStream with Java 13 #1827

adamretter opened this issue Nov 24, 2019 · 6 comments

Comments

@adamretter
Copy link

adamretter commented Nov 24, 2019

## Versions

  • Mockito: 3.1.0
  • JDK: 13.0.1+9
  • OS: macOS 10.13
  • XCode: 10.1-19

Code causing the error

InputStream in = mock(InputStream.class);

Error:

[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.015 s <<< FAILURE! - in uk.gov.nationalarchives.droid.core.interfaces.archive.ZipEntryRequestFactoryTest
[ERROR] testNewZipRequest(uk.gov.nationalarchives.droid.core.interfaces.archive.ZipEntryRequestFactoryTest)  Time elapsed: 0.005 s  <<< ERROR!
org.mockito.exceptions.base.MockitoException: 
Mockito cannot mock this class: class java.io.InputStream.
If you're not sure why you're getting this error, please report to the mailing list.
Java               : 13
JVM vendor name    : Oracle Corporation
JVM vendor version : 13.0.1+9
JVM name           : OpenJDK 64-Bit Server VM
JVM version        : 13.0.1+9
JVM info           : mixed mode, sharing
OS name            : Mac OS X
OS version         : 10.13.6
You are seeing this disclaimer because Mockito is configured to create inlined mocks.
You can learn about inline mocks and their limitations under item #39 of the Mockito class javadoc.
Underlying exception : org.mockito.exceptions.base.MockitoException: Could not modify all classes [class java.lang.Object, class java.io.InputStream, interface java.lang.AutoCloseable, interface java.io.Closeable]
	at uk.gov.nationalarchives.droid.core.interfaces.archive.ZipEntryRequestFactoryTest.testNewZipRequest(ZipEntryRequestFactoryTest.java:70)
Caused by: org.mockito.exceptions.base.MockitoException: Could not modify all classes [class java.lang.Object, class java.io.InputStream, interface java.lang.AutoCloseable, interface java.io.Closeable]
	at uk.gov.nationalarchives.droid.core.interfaces.archive.ZipEntryRequestFactoryTest.testNewZipRequest(ZipEntryRequestFactoryTest.java:70)
Caused by: java.lang.IllegalStateException: 
Byte Buddy could not instrument all classes within the mock's type hierarchy
This problem should never occur for javac-compiled classes. This problem has been observed for classes that are:
 - Compiled by older versions of scalac
 - Classes that are part of the Android distribution
	at uk.gov.nationalarchives.droid.core.interfaces.archive.ZipEntryRequestFactoryTest.testNewZipRequest(ZipEntryRequestFactoryTest.java:70)
Caused by: java.lang.IllegalArgumentException: Unsupported class file major version 57
	at uk.gov.nationalarchives.droid.core.interfaces.archive.ZipEntryRequestFactoryTest.testNewZipRequest(ZipEntryRequestFactoryTest.java:70)
@dmitry-timofeev
Copy link
Contributor

We had same issues with Java 13. I just overrode Mockito Byte Buddy dependency to a newer version (1.10.3), and it solved inline mock failures in our tests.

Submitted the upgrade in Mockito itself: #1828

@TimvdLippe
Copy link
Contributor

Please do not mock Inputstream, but create a real example with fake data instead. That said, we will update Byte Buddy to be compatible with Java 13.

TimvdLippe added a commit that referenced this issue Nov 28, 2019
Mocking types that users not own [1] or are severely complicating test
logic [2] leads to brittle or wrong tests. In particular, the
StackOverflow answer is wrong, as the contract of java.util.Map is
violated. When a new key is added to the Map, the stubbed return would be wrong.
In Google we have used the DoNotMock annotation via ErrorProne [3]
to annotate these types, as well as an internal list of types that can't
be mocked (this includes several java.util types). We are using a custom
Mockmaker to enforce this on run-time.

Based on our successful experience with DoNotMock (we have seen a large
reduction in bad/broken tests for types involved), we are proposing to
open source this into Mockito itself.

The DoNotMock annotation can be added to any type, e.g. classes and
interfaces. If, in the type hierarchy of the class-to-be-mocked, there
is a type that is annotated with DoNotMock, Mockito will throw a
DoNotMockException.

This would help preventing issues such as #1827 and #1734 which is
in-line with the guidance on our wiki [1]. A follow-up change would
allow us to define external types (like the java.util types) that can't
be mocked. (We can't add the annotation to the types, as they live in the
JDK instead.)

[1]: https://github.com/mockito/mockito/wiki/How-to-write-good-tests#dont-mock-a-type-you-dont-own
[2]: https://stackoverflow.com/a/15820143
[3]: https://errorprone.info/api/latest/com/google/errorprone/annotations/DoNotMock.html
@dmitry-timofeev
Copy link
Contributor

Thank you @TimvdLippe ! Would it be possible please to push this release to Maven Central? Creating inline mocks of any classes compiled with javac 13 does not work, not just platform classes like InputStream, so I think this release can be considered 'notable' according to the release policy.

@TimvdLippe
Copy link
Contributor

It is being released: d7c5ac4

@dmitry-timofeev
Copy link
Contributor

Wonderful, thanks!

@adamretter
Copy link
Author

Thanks everyone for the quick response :-)

TimvdLippe added a commit that referenced this issue Nov 19, 2021
Mocking types that users not own [1] or are severely complicating test
logic [2] leads to brittle or wrong tests. In particular, the
StackOverflow answer is wrong, as the contract of java.util.Map is
violated. When a new key is added to the Map, the stubbed return would be wrong.
In Google we have used the DoNotMock annotation via ErrorProne [3]
to annotate these types, as well as an internal list of types that can't
be mocked (this includes several java.util types). We are using a custom
Mockmaker to enforce this on run-time.

Based on our successful experience with DoNotMock (we have seen a large
reduction in bad/broken tests for types involved), we are proposing to
open source this into Mockito itself.

The DoNotMock annotation can be added to any type, e.g. classes and
interfaces. If, in the type hierarchy of the class-to-be-mocked, there
is a type that is annotated with DoNotMock, Mockito will throw a
DoNotMockException.

This would help preventing issues such as #1827 and #1734 which is
in-line with the guidance on our wiki [1]. A follow-up change would
allow us to define external types (like the java.util types) that can't
be mocked. (We can't add the annotation to the types, as they live in the
JDK instead.)

This PR also introduces the DoNotMockEnforcer interface which users can override
to implement their special handling of types annotated with DoNotMock.

[1]: https://github.com/mockito/mockito/wiki/How-to-write-good-tests#dont-mock-a-type-you-dont-own
[2]: https://stackoverflow.com/a/15820143
[3]: https://errorprone.info/api/latest/com/google/errorprone/annotations/DoNotMock.html
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