Skip to content

Mockito fails to mock non-public inner class in continuous testing due to classloading issues #38987

@famod

Description

@famod

Describe the bug

The following primitive test (and tested class):

@ExtendWith(MockitoExtension.class)
public class FooTest {

    @Mock
    private Foo.Inner mock;

    @Test
    public void test() {

    }
}
public class Foo {

    static class Inner {
    }
}

works fine in IDE or mvn, but fails with mvn quarkus:test:

ERROR [io.qua.test] (Test runner thread) Test FooTest#test() failed 
: org.mockito.exceptions.base.MockitoException: 
Mockito cannot mock this class: class org.acme.Foo$Inner.

Mockito can only mock non-private & non-final classes, but the root cause of this error might be different.
Please check the full stacktrace to understand what the issue is.
If you're still not sure why you're getting this error, please open an issue on GitHub.


Java               : 17
JVM vendor name    : Azul Systems, Inc.
JVM vendor version : 17.0.9+8-LTS
JVM name           : OpenJDK 64-Bit Server VM
JVM version        : 17.0.9+8-LTS
JVM info           : mixed mode, emulated-client, sharing
OS name            : Linux
OS version         : 5.15.0-94-generic


Underlying exception : org.mockito.exceptions.base.MockitoException: 
Cannot create mock for class org.acme.Foo$Inner

The type is not public and its mock class is loaded by a different class loader.
This can have multiple reasons:
 - You are mocking a class with additional interfaces of another class loader
 - Mockito is loaded by a different class loader than the mocked type (e.g. with OSGi)
 - The thread's context class loader is different than the mock's class loader
	at org.mockito.junit.jupiter.MockitoExtension.beforeEach(MockitoExtension.java:160)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	Suppressed: java.lang.NullPointerException: Cannot invoke "java.util.Set.forEach(java.util.function.Consumer)" because the return value of "org.junit.jupiter.api.extension.ExtensionContext$Store.remove(Object, java.lang.Class)" is null
		at org.mockito.junit.jupiter.MockitoExtension.afterEach(MockitoExtension.java:194)
		... 2 more
Caused by: org.mockito.exceptions.base.MockitoException: 
Cannot create mock for class org.acme.Foo$Inner

The type is not public and its mock class is loaded by a different class loader.
This can have multiple reasons:
 - You are mocking a class with additional interfaces of another class loader
 - Mockito is loaded by a different class loader than the mocked type (e.g. with OSGi)
 - The thread's context class loader is different than the mock's class loader
	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)
	... 3 more


ERROR [io.qua.test] (Test runner thread) >>>>>>>>>>>>>>>>>>>> Summary: <<<<<<<<<<<<<<<<<<<<
FooTest#test()

Expected behavior

No failure, should work as in IDE or mvn.

Actual behavior

Fails with classloading issue.

How to Reproduce?

  1. clone https://github.com/famod/q_ctest-inner
  2. mvn clean verify (passes)
  3. mvn quarkus:test fails

Output of uname -a or ver

No response

Output of java -version

No response

Quarkus version or git rev

3.7.4

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

The problem vanishes after adding public to the inner class.

I have another case where adding public helps, but that's not an inner class.

It has been an issue for many releases now, I just haven't found the time to report it.
I'm rather sure (IIRC) it was actually working some months ago.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Done

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions