Skip to content

Mockito agent doesn't work in an Eclipse OSGi environment #3457

@jhonnen

Description

@jhonnen

The following repro test fails in an Eclipse OSGi environment when Mockito is applied as a -javaagent.

package repro;

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

class MockitoTest {

    @Test
    void test() {
        var mock = Mockito.mock(org.slf4j.Logger.class);
        mock.debug("test");

        Mockito.verify(mock).debug("test");
        Mockito.verifyNoMoreInteractions(mock);
    }
}
org.mockito.exceptions.misusing.UnfinishedVerificationException: 
Missing method call for verify(mock) here:
-> at repro.MockitoTest.test(MockitoTest.java:13)

Example of correct verification:
    verify(mock).doSomething()

Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.

	at repro.MockitoTest.test(MockitoTest.java:14)

check that

  • The mockito message in the stacktrace have useful information, but it didn't help
  • The problematic code (if that's possible) is copied here;
    Note that some configuration are impossible to mock via Mockito
  • Provide versions (mockito / jdk / os / any other relevant information)
    • mockito:5.14.1
    • Java 21.0.4+7-LTS
    • Eclipse 2024-09
  • Provide a Short, Self Contained, Correct (Compilable), Example of the issue
    (same as any question on stackoverflow.com)
  • Read the contributing guide

Since I cannot provide a full self contained repro, here's what I could debug:

The created mocks do not have a mockInterceptor set because of a classloader conflict:
The classloader used to load the mock in org.mockito.internal.creation.bytebuddy.SubclassBytecodeGenerator#mockClass contains the following classloaders:

  1. the bundle of the mocked class ("X")
  2. mockito itself
  3. context classloader

When MockAccess is then loaded via that classloader, the EquinoxClassLoader for "X" is then queried first. That classloader will try to load the class from its parent (i.e. the app classloader) as a last resort.
When the agent is applied, it will find the class there and will not load it from Mockito's classloader.
--> instanceof MockAccess in org.mockito.internal.creation.bytebuddy.InlineDelegateByteBuddyMockMaker#doCreateMock is then always false:
image

A fix might be to reorder the classloaders of mockClass() so that Mockito is always queried first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions