Home > Back-end >  Mockito Long not Zero ArgumentMatcher
Mockito Long not Zero ArgumentMatcher

Time:04-11

I am trying to refactor very old Java legacy tests using Mockito (mockito-core)1.10.19 to Mockito 4.

I have in the legacy the following matcher

 private static long nonZeroLong() {
    return longThat(not(0L));
  }

that should provide arg matchers for the following mock

doAnswer(invocation -> {
      Runnable originalTask = invocation.getArgumentAt(0, Runnable.class);
      Runnable runnable = () -> {
             /*
                LOCK is need here to emulate waiting on ConcurrentHashMap.compute method.
                It is uses `synchronized` block internally, so any technique which can throw
                interrupted exception for waiting can't be used here
             */
        synchronized (LOCK) {
        }
        originalTask.run();
        scheduledFutureExecuted.set(true);
        futureExecutedSignal.countDown();
      };
      invocation.getArguments()[0] = runnable;
      ScheduledFuture res = (ScheduledFuture) invocation.callRealMethod();
      scheduledFutureRef.set(res);
      return res;
    }).when(pool).schedule(any(Runnable.class), nonZeroLong(), any());

I am not mockito-guro but on a very first place I am not sure at all that this original way was suitable at all for this invocation, however it is the original way was done.

Since in Mockito 4 this argument matcher does not exist anymore I refactored it as :

private static long nonZeroLong() {
    return  longThat(argument -> argument != 0);
  }

However I am still not sure what I provide will be the same as the original matcher in the legacy version.

My question is - will my matcher provide same logic as the original one?

CodePudding user response:

Behaviour is the same.
But in your case, you created the custom ArgumentMatcher.
Better to use mockito Additional Matchers not(eq(value))

    private static long nonZeroLong() {
        return not(eq(0L));
    }

At least they improve readability of errors output and they have flexible implementation for any type.
Mokito matcher output:

Argument(s) are different! Wanted:
bean.print(not(0L));                                // We see actual problem 
-> at TestObject.testZeroMathers(TestObject.java:28)
Actual invocations have different arguments:
bean.print(0L);
-> at TestObject.testZeroMathers(TestObject.java:26)

Custom matcher output:

Argument(s) are different! Wanted:
bean.print(<custom argument matcher>);              // We do not see actual problem
-> at TestObject.testZeroLongThat(TestObject.java:35)
Actual invocations have different arguments:
bean.print(0L);
-> at TestObject.testZeroLongThat(TestObject.java:33)

Example of test:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Spy;

import org.mockito.junit.MockitoJUnitRunner;

import static org.mockito.AdditionalMatchers.not;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class TestObject {

    @Spy
    Bean bean = new Bean();

    @Test
    public void test() {
        bean.print(1L);

        verify(bean, times(1)).print(nonZeroLong());
        verify(bean, times(1)).print(nonZeroLongThat());
    }

    @Test
    public void testZeroMathers() {
        bean.print(0L);

        verify(bean, times(1)).print(nonZeroLong());
    }

    @Test
    public void testZeroLongThat() {
        bean.print(0L);

        verify(bean, times(1)).print(nonZeroLongThat());
    }

    private static long nonZeroLongThat() {
        return  longThat(argument -> argument != 0);
    }

    private static long nonZeroLong() {
        return not(eq(0L));
    }
}

public class Bean {
    public void print(Long l) {
        System.out.println("Hi, I'm Bean "   l);
    }
}
  • Related