Fazecast / jSerialComm

Platform-independent serial port access for Java
GNU Lesser General Public License v3.0
1.35k stars 287 forks source link

Broken unit tests due to android dependencies #528

Closed rodrigo-rassystem closed 1 year ago

rodrigo-rassystem commented 1 year ago

Hello, we are using JSerialComm in our project and we have some JUnit tests that use a "mock" from SerialPort, like this:

SerialPort serialPortMock = Mockito.mock(SerialPort.class);

Until version 2.9.3 this mock works well, but in version 2.10.3 it stopped working due to an error. The relevant part of the error is:

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

We tried to remove mockito from this test but it is impossible to create an instance of SerialPort since it´s constructor is private.

We don´t want to stop testing, but with Android dependencies in the JAR it is not possible anymore.

I can think in some possible solutions: 1) release a JSErialComm.jar version without Android dependencies. 2) refactor the code to make SerialPort an interface so it will be easier to mock. 3) create a static method to make a "mocked" SerialPort for people that want to write unit tests.

Following the trace error:

org.mockito.exceptions.base.MockitoException: 
Mockito cannot mock this class: class com.fazecast.jSerialComm.SerialPort.

If you're not sure why you're getting this error, please open an issue on GitHub.

Java               : 17
JVM vendor name    : Eclipse Adoptium
JVM vendor version : 17.0.5+8
JVM name           : OpenJDK 64-Bit Server VM
JVM version        : 17.0.5+8
JVM info           : mixed mode
OS name            : Windows 10
OS version         : 10.0

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 com.fazecast.jSerialComm.SerialPort]
Caused by: org.mockito.exceptions.base.MockitoException: Could not modify all classes [class com.fazecast.jSerialComm.SerialPort]
    at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:168)
    at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:399)
    at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:190)
    at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:410)
    ... 5 more
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 org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.triggerRetransformation(InlineBytecodeGenerator.java:285)
    at org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.mockClass(InlineBytecodeGenerator.java:218)
    at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.lambda$mockClass$0(TypeCachingBytecodeGenerator.java:78)
    at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:168)
    at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:399)
    at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:190)
    at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:410)
    at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.mockClass(TypeCachingBytecodeGenerator.java:75)
    at org.mockito.internal.creation.bytebuddy.InlineDelegateByteBuddyMockMaker.createMockType(InlineDelegateByteBuddyMockMaker.java:396)
    at org.mockito.internal.creation.bytebuddy.InlineDelegateByteBuddyMockMaker.doCreateMock(InlineDelegateByteBuddyMockMaker.java:355)
    at org.mockito.internal.creation.bytebuddy.InlineDelegateByteBuddyMockMaker.createMock(InlineDelegateByteBuddyMockMaker.java:334)
    at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker.createMock(InlineByteBuddyMockMaker.java:56)
    at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:99)
    at org.mockito.internal.MockitoCore.mock(MockitoCore.java:88)
    at org.mockito.Mockito.mock(Mockito.java:2101)
    at org.mockito.Mockito.mock(Mockito.java:2016)
    ... 5 more
Caused by: java.lang.NoClassDefFoundError: android/app/Application
    at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
    at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3402)
    at java.base/java.lang.Class.getDeclaredMethods(Class.java:2504)
    at net.bytebuddy.description.method.MethodList$ForLoadedMethods.<init>(MethodList.java:152)
    at net.bytebuddy.description.type.TypeDescription$ForLoadedType.getDeclaredMethods(TypeDescription.java:8940)
    at net.bytebuddy.dynamic.scaffold.InstrumentedType$Factory$Default$1.represent(InstrumentedType.java:438)
    at net.bytebuddy.ByteBuddy.redefine(ByteBuddy.java:886)
    at net.bytebuddy.ByteBuddy.redefine(ByteBuddy.java:861)
    at org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.transform(InlineBytecodeGenerator.java:390)
    at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:244)
    at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
    at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:541)
    at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
    at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:169)
    at org.mockito.internal.creation.bytebuddy.InlineBytecodeGenerator.triggerRetransformation(InlineBytecodeGenerator.java:281)
    ... 20 more
Caused by: java.lang.ClassNotFoundException: android.app.Application
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
    ... 35 more
hedgecrw commented 1 year ago

I think this was already addressed in Issue #512 (with the fix to be included in the upcoming release). Just to verify, please try the following snapshot and see if it works for you:

SNAPSHOT Version: 2.10.4-SNAPSHOT SNAPSHOT Direct Download Link SNAPSHOT Instructions

rodrigo-rassystem commented 1 year ago

Version 2.10.4-SNAPSHOT worked. Thank you.

hedgecrw commented 1 year ago

Fixed with v2.10.4 release