Skip to content

Method Only.verify throws NullPointerException #3237

@ilia-sretenskii

Description

@ilia-sretenskii

Method Only.verify throws NullPointerException with the latest mockito-core 5.9.0

Here is a sample code in Kotlin which triggers this issue.

verify(service, only()).doSomething()

It triggers the following NullPointerException to be thrown.

java.lang.NullPointerException: Cannot invoke "org.mockito.invocation.Invocation.getMock()" because "undesired" is null
	at org.mockito.internal.exceptions.Reporter.noMoreInteractionsWanted(Reporter.java:555)
	at org.mockito.internal.verification.Only.verify(Only.java:30)
	at org.mockito.internal.verification.MockAwareVerificationMode.verify(MockAwareVerificationMode.java:30)
	at org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:75)
	at org.mockito.internal.handler.NullResultGuardian.handle(NullResultGuardian.java:29)
	at org.mockito.internal.handler.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:34)
	at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:82)
	at org.mockito.internal.creation.bytebuddy.MockMethodAdvice.handle(MockMethodAdvice.java:134)

A quick analysis shows that it is caused by method Only.verify which searches for an optional unverified invocation by execution of method InvocationsFinder.findFirstUnverified, but then fails to check for the result for null and just calls method Reporter.noMoreInteractionsWanted which throws the exception because the invocation was not found.
https://github.com/mockito/mockito/blob/main/src/main/java/org/mockito/internal/verification/Only.java#L29C37-L30

        MatchableInvocation target = data.getTarget();
        List<Invocation> invocations = data.getAllInvocations();
        List<Invocation> chunk = findInvocations(invocations, target);
        if (invocations.size() != 1 && !chunk.isEmpty()) {
            Invocation unverified = findFirstUnverified(invocations);
            throw noMoreInteractionsWanted(unverified, (List) invocations);
        }

Note that there is method NoMoreInteractions.verify which also makes a call to the same two methods InvocationsFinder.findFirstUnverified and Reporter.noMoreInteractionsWanted but it does so properly, thus the exception can not be thrown there.
https://github.com/mockito/mockito/blob/main/src/main/java/org/mockito/internal/verification/NoMoreInteractions.java#L25-L28

        Invocation unverified = findFirstUnverified(data.getAllInvocations());
        if (unverified != null) {
            throw noMoreInteractionsWanted(unverified, (List) data.getAllInvocations());
        }

So I suggest that the same check for null would be made in method Only.verify to avoid the exception.
And I also suggest that static analysis based on annotations would be introduced, then it would be obvious that method findFirstUnverified returns a nullable value while method noMoreInteractionsWanted does not accept a nullable argument.

  • 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)
  • Provide a Short, Self Contained, Correct (Compilable), Example of the issue
    (same as any question on stackoverflow.com)
  • Read the contributing guide

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