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 enum with methods fails on Java 17 #2315
Comments
This might be related to openjdk/jdk#4015 |
I thought about that as well, but that one mostly results in errors like But maybe that error is swallowed somewhere. |
When I run this on a recent JDK 17, it all works. The underlying error is: java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the class NestHost, NestMembers, Record, or PermittedSubclasses attribute. Normally, this indicates that BB changed an attribute but this would surprise me. |
Thanks for checking it, I've upgraded to the latest OpenJDK and the latest Mockito. But the error is still there: `[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 2.287 s <<< FAILURE! - in com.example.ExampleEnumTest Mockito cannot mock this class: class com.example.ExampleEnum. If you're not sure why you're getting this error, please report to the mailing list. Java : 17 You are seeing this disclaimer because Mockito is configured to create inlined mocks. Underlying exception : org.mockito.exceptions.base.MockitoException: Could not modify all classes [class java.lang.Object, class java.lang.Enum, interface java.lang.Comparable, interface java.io.Serializable, class com.example.ExampleEnum, interface java.lang.constant.Constable] How did you run the example? Did you use use my GitHub project https://github.com/johanjanssen/JavaUpgrades/tree/main/java17/mockito_broken? Or did you create your own based on the code I pasted above? I wonder if the error then has something to do with the dependencies I'm using. |
I've just double checked by running my GitHub repo example in Docker images. It fails with maven:3.8.1-openjdk-17-slim and succeeds with maven:3.8.1-openjdk-16-slim. I really wonder what's the difference between our setups :-). |
I did find the problem after all. It seems like permitted subclasses are appended twice upon a retransformation what sets of the verifier. I need to see why this happens and will fix this as soon as I find the time. |
I identified the issue, it seems to be a bug or a documentation issue in ASM: https://gitlab.ow2.org/asm/asm/-/issues/317948 I will create a new version once that is resolved. |
Interesting, thanks a lot for your help! |
Fixed it on master, it's a documentation error in ASM so I don't have to wait for a release. I have some other minor issues I have to address but it will be fixed eventually. |
Just tried my example on the newly released 3.11.2. Now it works! Thanks a lot @raphw for fixing it so soon! |
Mocking enums isn't working for me on Java 17, even with 3.11.2. I get a |
Yeah, sealed types put an end to this. We should however supply better error messages: #2392 |
I guessed that was probably the case. In #2392 you say "sealed classes can only be mocked if they are real inline mocks." What do you mean by "real inline mocks"? Is there some workaround to mock sealed classes? |
The inline mock maker needs to create subclasses when mocking abstract types or interfaces. Otherwise the classes cannot be instantiated. If those mocks are sealed, we are out of luck. |
With version 3.12.4, I see exceptions that originate with:
...but only when a security manager is active on Java 17. |
Can you provide a full stack? |
@raphw I have narrowed the issue down some -- I can reproduce the problem with mockito 3.11.2, but not with 3.11.1. Here is the full stack from 3.12.4:
Test is:
|
I see, I still struggle to get the security manager under control after I had to create some custom abstractions in order to address the cut down that was introduced in Java 17. I have just pushed a new appraoch to Byte Buddy that hopefully avoids the issue altogether. Could you checkout Byte Buddy and build it from master and try with the patched version? |
Nice! I can confirm that when using bytebuddy version 1.11.14 my test fails, but 1.11.15-SNAPSHOT causes it to succeed 🥇 |
Hello guys, I can confirm that I still get a fairly similar issue with Java 17, Mockito 3.12.4 and Byte Buddy 1.11.18 Test package net.lewox.mockito;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
class MockEnum {
@Test
void testMockEnum() {
Mockito.mock(Animal.class);
}
enum Animal {
CAT {
@Override
public String sound() {
return "meow";
}
};
public abstract String sound();
}
} Stacktrace
|
I added this as a test case to Mockito and it seems to work just fine: https://github.com/mockito/mockito/blob/main/subprojects/inline/src/test/java/org/mockitoinline/EnumMockingTest.java Are you using the latest version and inline mock maker? |
Hi @raphw I'm using the versions I described above (Java 17, Mockito 3.12.4 and Byte Buddy 1.11.18), I tested both with the ByteBuddy version currently used and version 1.11.18, and I'm depdencency mockito-inline as well (same version as mockito). openjdk version "17" 2021-09-14 and Windows 10 On a side note, I cannot build clean version 3 tests fail, using Gradle wrapper. |
Strange. Our CI disagrees: https://github.com/mockito/mockito/runs/3699826916?check_suite_focus=true Not sure why there would be a difference on Windows. Could you download the exact JVM version that we are using and try again? |
Closing this per the above comment. If you can still reproduce this issue, please submit a regression test to our test suite and we can debug further, thanks! |
@pburka Did you find a workaround? I got same issue |
Mocking enums is probably a dubious practice. If the enum represents a
closed set, you shouldn't be adding a new member at test time.
If you're using an enum as a convenient way to hold a set of singletons,
then add an interface which the enum can implement and mock that, instead.
Peter
…On Mon, Nov 7, 2022, 6:56 PM jonatanloya ***@***.***> wrote:
Mocking enums isn't working for me on Java 17, even with 3.11.2. I get a java.lang.IncompatibleClassChangeError:
class ...$MockitoMock$549794057 cannot inherit from sealed class ....
@pburka <https://github.com/pburka> Did you find a workaround? I got same
issue
—
Reply to this email directly, view it on GitHub
<#2315 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AA6GRS46MXCQMLY7VYHUDIDWHGJJTANCNFSM46CV2T2A>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
@pburka could you kindly give an example of adding the interface to mock the enum (set of singletons in my use case as well). |
The approach here is to change your program so you don't have to mock enums.
Say your enum is called Color and it's got members MAUVE, BEIGE and AMBER,
and you want to mock a new color for testing. You can't, though, because
enums are closed sets. To fix this:
1. Rename the enum to Colors (with an S)
2. Add an interface Color with whatever methods the enum implements
3. Add the interface to the enum: enum Colors implements Color
4. Now you can mock the interface, because interfaces aren't closed sets
…On Wed, Nov 9, 2022, 6:02 PM Namdi ***@***.***> wrote:
@pburka <https://github.com/pburka> could you kindly give an example of
adding the interface to mock the enum (set of singletons in my use case as
well).
—
Reply to this email directly, view it on GitHub
<#2315 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AA6GRS5FSC73PXVZNMAPZVTWHQUPLANCNFSM46CV2T2A>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
I was having the same issue, and as others have said, I can confirm that the only way I could solve the issue is not mocking sealed classes anymore. My scenario looked like the following
I had to remove all references to |
The following fails on Java 17 and works on 11 and 16:
On 17 it gives the following error:
The complete code example can be found here: https://github.com/johanjanssen/JavaUpgrades/tree/main/java17
It can be build with Docker for instance with (17 can be replaced with 11 and 16):
docker build -t javaupgrades -f ..\Dockerfile --build-arg JDK_VERSION=17 .
Is there some way I can work around this issue?
The text was updated successfully, but these errors were encountered: