Hot questions for Using Mockito in argument matcher

Top 10 Java Open Source / Mockito / argument matcher

Question:

I am trying to mock a class and return a stubbed list of objects when a method on the mocked object is called. Lets consider following code :

interface MyRepositry{
       public List<MyClass> getMyClassInstances(String str,Long id,List<Integer> statusList);
}

I am mocking above method ivocation as follows :

when(myRepository.getMyClassInstances("1234", 200L, stubbedList)).thenReturn(stubbedMyClassInstanceList);

where

 stubbedList 

is the list I create by inserting two integers 1 and 3. In real call also I pass the list I construct which has integers 1 and 3. Point ot note here is stubbedList object and the list object in real call are different but always contain two integers 1 and 3.

stubbedMyClassInstanceList    

is the stubbed list of MyClass instances.

However mockito return an empty list when i run the test. I did some debugging and I guess mockito is not able to match the list object that I am using in

      when(..).thenReturn(..)

call and in actual call and hence doesn't find the correct signature.

I cannot use

anyList() 

matcher as I always pass list of two integers (1 and 3).

I have resolved the problem by using custom

     ArgumentMatcher 

as follows :

     class StatusMatcher extends ArgumentMatcher<List> {
    public boolean matches(Object list) {
        List statuses = ((List) list);
        return (statuses.size() == 2 && statuses.contains(1) && statuses.contains(3));
    }
}

So the question is :

1) Is my guess about why the stubbing/mocking not working correct? 2) and is the solution I have used correct?


Answer:

Mockito naturally uses equals() for argument matching. The equals() method in List<T> specifies that two lists are defined to be equal if they contain the same elements in the same order.

Your custom argument matcher, that you say works, is not considering order.

So maybe the 1 and 3 are in the wrong order in the List<T>?

Question:

I have method:

public void loadPlatformDependencies() {
    try {
        dependenciesRepository.deleteAll();
        dependenciesRepository.saveAll(pullLastDependencies());
        publisher.publishEvent(new LoadedDependenciesEvent());
    } catch (Exception e) {
        LOGGER.error("Failed to load dependencies", e);
    }
}

And I try to test it:

   @Test
    public void testLoadPlatformDependencies() {
        ArgumentCaptor<Iterable<Dependency>> captor = ArgumentCaptor.forClass(Iterable.class);
        when(dependenciesRepository.saveAll(captor.capture())).thenReturn(any(Iterable.class));
        puller.loadPlatformDependencies();

        verify(dependenciesRepository,times(1)).deleteAll();
        verify(dependenciesRepository, times(1)).saveAll(any(Iterable.class));
        verify(publisher,times(1)).publishEvent(any());

   }

But there are a problem, that method pullLastDependencies() work incorect now. I have a mistake:

Invalid use of argument matchers!
0 matchers expectd, 1 recorded:

Method pullLastDependencies() returns List. Can I test this method without a properly working method pullLastDependencies()? Or maybe I should test this method in another way?


Answer:

You're using the captor in when() instead of verify(). And you're returning any() (which is just null) from your mocked method, instead of returning what you want this mock to return. if you don't care about what it returns because you don't use it, then return an empty iterable.

It should be

when(dependenciesRepository.saveAll(any()).thenReturn(Collections.emptyList());
puller.loadPlatformDependencies();

verify(dependenciesRepository).deleteAll();
verify(dependenciesRepository).saveAll(captor.capture());

Question:

Although the error is quite descriptive I could not get a hang of it. For lines:

    PowerMockito.when(
            mockStringMessageService.lookupString(Matchers.eq("XYZ")))
            .thenReturn(Matchers.eq("XYZ"));

Error is:

[junit] Invalid use of argument matchers!
[junit] 0 matchers expected, 1 recorded:
[junit] -> at com.amazon.kilvish.types.StatusTableTest.setUp(StatusTableTest.java:61)
[junit] 
[junit] This exception may occur if matchers are combined with raw values:
[junit]     //incorrect:
[junit]     someMethod(anyObject(), "raw String");
[junit] When using matchers, all arguments have to be provided by matchers.
[junit] For example:
[junit]     //correct:
[junit]     someMethod(anyObject(), eq("String by matcher"));
[junit] 
[junit] For more info see javadoc for Matchers class.

Why are 0 matchers expected?


Answer:

You cannot use matchers in the thenReturn clause. Just use the string literal instead:

PowerMockito.when(
        mockStringMessageService.lookupString(Matchers.eq("XYZ")))
        .thenReturn("XYZ");

Question:

I'm using mockito-core:2.8.47 and Java 7 and want to use in a when and verify anyListOf or some other any method. My Problem is, if I just use anyList it says:

The method name( int, List < List < String > >) in the type Y is not applicable for the arguments ( int, List < Object > )

How can I fix this?

ArgumentMatchers.anyListOf(ArgumentMatchers.anyListOf( String.class ) ) doesn't work...


Answer:

In my opinion you can get away with just the basic anyList() method with additional generics information:

Mockito.doReturn("1").when(classMock).name(ArgumentMatchers.eq(1)
                , ArgumentMatchers.<List<String>>anyList());

This worked for me and also remember to add the ArgumentMatcher for the first int variable otherwise Mockito will fail.

Question:

I am using eclipse to run some unit tests on a class and I am using Mockito so I don't have to connect to the database. I have used anyString() in other tests which works but it isn't working in this test. If I change it from anyString() to "" the error disappears and the test passes.

My test is:

@Test
public void test_GetUserByUsername_CallsCreateEntityManager_WhenAddUserMethodIsCalled() {

    //Arrange
    EntityManagerFactory mockEntityManagerFactory = mock(EntityManagerFactory.class);
    EntityManager mockEntityManager= mock(EntityManager.class);
    UserRepositoryImplementation userRepositoryImplementation = new UserRepositoryImplementation();
    userRepositoryImplementation.setEntityManagerFactory(mockEntityManagerFactory);

    when(mockEntityManagerFactory.createEntityManager()).thenReturn(mockEntityManager);


    //Act
    userRepositoryImplementation.getUserByUsername(anyString());

    //Assert
    verify(mockEntityManagerFactory, times(1)).createEntityManager();

}

Can anyone explain why I am getting the error and what I can do to resolve it?


Answer:

userRepositoryImplementation.getUserByUsername(anyString());

This is not the right use of anyString(). It can be used for stubbing or for verifying. But not for actual call of method. From documentation:

Allow flexible verification or stubbing.

If you want a random string when test is running try to use RandomStringUtils or any other similar library.

userRepositoryImplementation.getUserByUsername(RandomStringUtils.random(length));

Question:

Mockito.when(metadataDao.getStuff(Mockito.anyInt()).get(Mockito.anyInt()))
               .thenReturn(returnedVariable);

I'm getting the following error:

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
    at java.util.LinkedList.checkElementIndex(LinkedList.java:555)
    at java.util.LinkedList.get(LinkedList.java:476)
    at 

Why can't I use the matchers?


Answer:

Mockito.anyInt() works via side-effects; when it passes the value to a real class, it essentially sends 0.

It looks like metadataDao.getStuff is returning a real LinkedList, with size 0. Then, you send what amounts to 0 to that real LinkedList, which calls the real get method with size 0, and you get the normal error you expect.

You can avoid problems like this by not ever using chained method calls inside Mockito, in other words, never do:

when(obj.methodOne().methodTwo())

Instead, just use one method call. In your example, this might be:

List<MyObj> mockList = Mockito.mock(List.class);
Mockito.when(metadataDao.getStuff(Mockito.anyInt()).thenReturn(mockList);
Mockito.when(mockList.get(Mockito.anyInt())).thenReturn(returnedVariable);

Also note that, as @JeffBowman points out in the comments, you should never be mocking List when a real List will do.

Question:

Test

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MockabstractionApplication.class)
public class SimpleTest {

    @SpyBean
    private SimpleService spySimpleService;

    @Before
    public void setup() {
        initMocks(this);
    }

    @Test //fails
    public void test() throws Exception {
        when(spySimpleService.test(1, Mockito.<String>anyVararg())).thenReturn("Mocked!");
    }

}

Service

@Service
public class SimpleService {

    public String test(int i, String... args) {
        return "test";
    }

}

Test fails with the next message:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers! 2 matchers expected, 1 recorded:

I have to use int as 1st argument and any amount of varargs.


Answer:

If you use matchers for one parameter you have to use it for all parameters.

when(spySimpleService.test(Mockito.eq(1), Mockito.<String>anyVararg())).thenReturn("Mocked!");

Question:

I have this Scala project that I am using mockito (mockito-core 3.0) to test

Here's the function signature of the function I am trying to mock

def hset[V: ByteStringSerializer](key: String, field: String, value: V): Future[Boolean] = ...

This doesnt work

verify(mockObj, never()).hset(anyString(), anyString(), anyLong())

Error outs with this

Invalid use of argument matchers!
4 matchers expected, 3 recorded:

Not sure why its expecting 4 matchers when the function has 3 argument with a generics type

This works

verify(mockObj, never()).hset("a", "b", 3.0)

is this because I am using scala code which doesnt operate correctly with the mockito core ?


Answer:

The reason for the problem is context bound

def hset[V: ByteStringSerializer](key: String, field: String, value: V): Future[Boolean]

is actually

def hset[V](key: String, field: String, value: V)(implicit ev: ByteStringSerializer[V]): Future[Boolean]

Now you can see why there are 4 arguments, try

verify(mockObj, never()).hset(anyString(), anyString(), anyLong())(any(classOf[ByteStringSerializer[Long]]))

Question:

I'm writing unit tests in scala using MockitoSugar. I'm using org.mockito.Mockito.when and org.mockito.Matchers.anyString. The method under test is shown below.

def getDataSourceToDataFrame(database: scala.Predef.String, tableName: scala.Predef.String): DataFrame = {
glueContext.getCatalogSource(
  database = database,
  tableName = tableName,
  transformationContext = database + "." + tableName + ".read")
  .getDynamicFrame()
  .toDF()

}

Here is what my unit test looks like:

import com.amazon.rrsetlglue.glue.wrappers.WrappedGlueContext
import com.amazonaws.services.glue.{DynamicFrame, GlueContext, DataSource}
import org.scalatest.{BeforeAndAfter, FunSuite, Matchers}
import org.apache.spark.sql.DataFrame
import org.mockito.Mockito.when
import org.mockito.Matchers.anyString
import org.scalatest.junit.JUnitRunner
import org.junit.runner.RunWith
// Use Mockito because ScalaMock does not work with Glue
@RunWith(classOf[JUnitRunner])
class WrappedGlueContextTest extends FunSuite with 

org.scalatest.mockito.MockitoSugar with BeforeAndAfter  {

  var mockGlueContext : GlueContext = _
  var wrappedGlueContext: WrappedGlueContext = _

  before {
    mockGlueContext = mock[GlueContext]
    wrappedGlueContext = new WrappedGlueContext(mockGlueContext)
  }


 test("Test get dataFrame from glue data catalog source") {

    val mockedDataSource: DataSource= mock[DataSource]
    val mockDynamicFrame: DynamicFrame = mock[DynamicFrame]
    val mockDataFrame: DataFrame = mock[DataFrame]
    assert(wrappedGlueContext.glueContext === mockGlueContext)

    when(mockGlueContext.getCatalogSource(anyString, anyString, anyString)).thenReturn(mockedDataSource)

 }
}

The last when() call throws the error below:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers! 0 matchers expected, 3 recorded: This exception may occur if matchers are combined with raw values: //incorrect: someMethod(anyObject(), "raw String"); When using matchers, all arguments have to be provided by matchers. For example: //correct: someMethod(anyObject(), eq("String by matcher")); For more info see javadoc for Matchers class.

The definition for getCatalogSource() is shown below

 def getCatalogSource(database: String, tableName: String, redshiftTmpDir: String = "",
                   transformationContext: String = "", pushDownPredicate: String = "",
                   additionalOptions: JsonOptions = JsonOptions.empty, catalogId: String = null): DataSource = {

Why is it saying 0 matchers expected when I'm calling the method getCatalogSource() on a mocked object?


Answer:

The issue was that getCatalogSource() had default parameters that I wasn't passing in using my matchers. I changed the method call in the test to

 when(mockGlueContext.getCatalogSource(anyString, anyString, anyString, anyString, anyString, any(), any())).thenReturn(mockedDataSource)

and the test passed.

Question:

I need an ArgumentMatcher accepting any type of values in an Object array (Object[]). TestObject:

class ObjectArrayMethod {
    public int call(Object... objects) {
        return 0;
    }
}

I tried these, where all assertEquals are failing:

    ObjectArrayMethod method = Mockito.mock(ObjectArrayMethod.class);

    Object[] arg = {"", ""};
    Mockito.when(method.call(AdditionalMatchers.aryEq(arg))).thenReturn(15);
    int actual = method.call(arg);
    assertEquals(15, actual);

    ObjectArrayMethod method = Mockito.mock(ObjectArrayMethod.class);

    Mockito.when(method.call(any(Object[].class))).thenReturn(15);
    Object[] arg = new Object[] {null, null};
    int actual = method.call(arg);
    assertEquals(15, actual);

even failing:

    ObjectArrayMethod method = Mockito.mock(ObjectArrayMethod.class);

    Object[] arg = {"", ""};
    Mockito.when(method.call(AdditionalMatchers.aryEq(arg))).thenReturn(15);
    int actual = method.call(arg);
    assertEquals(15, actual);

I wrote an own Matcher:

    protected static class ObjectArrayArgumentMatcher implements ArgumentMatcher<Object[]>, VarargMatcher {

    private static final long serialVersionUID = 3846783742617041128L;
    private final Object[] values;
    private ErrorState errorState = NO_ERROR;

    protected ObjectArrayArgumentMatcher(Object[] values) {
        this.values = values;
    }

    @Override
    public boolean matches(Object[] argument) {

        if (values == null) {
            return true;
        }

        if (argument == null) {
            return false;
        }

        return true;
    }

}

and

    protected static class ObjectArrayArgumentMatcher2 extends ObjectArrayArgumentMatcher {

    private static final long serialVersionUID = 3085412884910289910L;

    protected ObjectArrayArgumentMatcher2(Object... values) {
        super(values);
    }

    @Override
    public boolean matches(Object... argument) {
        return super.matches(argument);
    }

}

Which I initialize with null values. But I's not called.

Of cause the next step is to compare arguments.

Why is neighter matches(Object[] argument) nor matches(Object... argument) called, with args {"", ""} or even {null, null}?

What I need is an ArgumentMatcher, that works for any Object array, even with mixed types like {"String", 1, new Object()}.

The method I finally want to mock is

int org.springframework.jdbc.core.JdbcTemplate.update(String sql, Object... args) throws DataAccessException

I am using

            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>2.22.0</version>

Btw. with Version 1.10.19 my ObjectArrayArgumentMatcher worked.


Answer:

Finally this post helped me for the solution: How to properly match varargs in Mockito

This works:

Mockito.when(method.call(ArgumentMatchers.<Object>any())).thenReturn(10);

Question:

I'm trying to mock a method of EntityPersistor

T getSingleResultFromTypedQuery(String queryString, Map<String, Object> params);

I want to check if queryString matches a specific queryString and if params contains a specific value. If those two conditions are true, I want to return an specific object xy.

I'm new to mocking and mockito, but I tried to achieve this with two ArgumentMatcher inside the when() call.

EntityPersistor<UserEntity> entityPersistorMocked = mock(EntityPersistorStub.class);

when(entityPersistorMocked.getSingleResultFromTypedQuery(argThat(new ArgumentMatcher<String>() {
        @Override
        public boolean matches(Object o) {
            return "SELECT u FROM UserEntity u where u.username = :u".equals(o.toString());
        }
    }), argThat(new ArgumentMatcher<Map<String, Object>>() {
        @Override
        public boolean matches(Object o) {
            HashMap<String, Object> params = (HashMap<String, Object>) o;
            if (params.containsKey('u') && params.get('u').toString().equals("hans")) {
                return true;
            } else {
                return false;
            }
        }
    })))
            .thenAnswer(new Answer<UserEntity>() {
                @Override
                public UserEntity answer(InvocationOnMock invocation) throws Throwable {
                    UserEntity user = new UserEntity();
                    user.setUserId(1);
                    user.setDisplayName("Dummy User");
                    user.setUsername("hans");
                    user.setPassword("pass");
                    return user;
                }
            });

compiles successfull but won't run:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 

Misplaced argument matcher detected here:

how can I fix that? or is there a better way to mock a method and define a specific return case (if param 1 eq x and param 2 eq y)?


Answer:

I'd just do:

Answer<UserEntity> answer = new Answer<UserEntity>() {
   public UserEntity answer(InvocationOnMock invocation) throws Throwable {
       String queryString = (String) invocation.getArgument(0);
       Map params = (Map) invocation.getArgument(1);
       if ("foo".equals(queryString) && params.containsKey("bar")) {
          return x;
       } else {
          return y;
       }
   }
};
when(mock.getSingleResultFromTypedQuery(anyString(), any(Map.class)).thenAnswer(answer);

Question:

I have the following code

public MessageProcessorTest() {
    _logger = mock(Logger.class);
    _context = mock(ExecutionContext.class);

    when(_context.getLogger()).thenReturn(_logger);
    doNothing().when(_logger).log(any(), anyString());

    _mapper = mock(IMapper.class);

    _processor = new MessageProcessor(_mapper, _context);
}

@Test
public void testOutputSourceIsMapped() throws SentenceException
{
    String inputString = "some string";
    when(_mapper.Map(any())).thenReturn(any());

    _inputMessage = new ProcessMessage(inputString, new Date().toString());

    ProcessResult result = _processor.Process(_inputMessage);

    assertNotNull(result);
    assertNotNull(result.GetOriginalMessage());
    assertNotNull(result.OutputMessage);
    assertTrue(result.IsSuccessful);

    Raw rawResult = new Gson().fromJson(result.OutputMessage, Raw.class);

    assertEquals(FeedSources.S.toString(), rawResult.GetSource());
}

And I get the following error

detailMessage:"\nInvalid use of argument matchers!\n0 matchers expected, 1 recorded:\n-> at com.emsa.hpims.processor.MessageProcessorTest.testOutputSourceIsMappedToSatAis(MessageProcessorTest.java:61)\n\nThis exception may occur if matchers are combined with raw values:\n    //incorrect:\n    someMethod(anyObject(), "raw String");\nWhen using matchers, all arguments have to be provided by matchers.\nFor example:\n    //correct:\n    someMethod(anyObject(), eq("String by matcher"));\n\nFor more info see javadoc for Matchers class.\n"

When executing the following line

_context.getLogger().log(Level.FINE, "Some log message");

I've read a bit about it but i'm not understanding what exactly am I doing wrong. Is anyone able to help me?

Thank you.


Answer:

The problem is most likely this line:

when(_mapper.Map(any())).thenReturn(any());

Here, you tell Mockito to return any() (which returns a matcher) when mapper.map() is invoked with anything.

The whole point with mocking is to allow the user to specify exactly what is returned by mocked methods. You have basically told Mockito to return anything when the method is called, which is not allowed.

What should the method return for you to allow to implement the test case? Replace the second any() with that.

Question:

I have seen someone creating a custom argument matcher like the following. However, I am having difficulty understanding how it works.

What I can understand its a method that takes a parameter and returns a ArgumentMatcher which is an interface that has a type of List<Person>. And the overriden method is the matcher that uses a lambda. I think the body part is the most confusing, if anyone can explain that.

private ArgumentMatcher<List<Person> personListSize(final int size) {
        return argument -> argument.personList().size() == size;
}

This is the way I would normally do something like this, which to me is easier to understand, just wondering how can I get the following to look like the above?

public class CustomArgumentMatcher implements ArgumentMatcher<List<Person>> {

    @Override
    public boolean matches(List<Person> argument) {
        return argument.size() == size;
    }
}

Just starting to understand, this works:

 private ArgumentMatcher<String> stringMatcher = new ArgumentMatcher<String>() {
        @Override
        public boolean matches(String argument) {
            return argument.contains("");
        }
    };

However, If I add a parameter to pass in like this:

 private ArgumentMatcher<String> stringMatcherArgs(final String name) = new ArgumentMatcher<String>() {
}

I get a error message saying unexpected token just wondering to pass in a parameter in the above?


Answer:

You should read this document about Lambda Expressions

Here are your examples:

private ArgumentMatcher<List<Person>> customArgumentMatcher(final int size) {
    return argument -> argument.size() == size;
}
private ArgumentMatcher<List<Person>> stringMatcherArgs(final String name) {
    return argument -> argument.contains(name);
}