Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito when checking for specific object property value

Tags:

java

mockito

I have the following in a working test:

when(client.callApi(anyString(), isA(Office.class))).thenReturn(responseOne);

Note that client is a Mock of class Client.

I want to change "isA(Office.class)" to tell it to match where the "id" property of an Office instance is "123L". How can I specify that I want a specific argument value in the method of a mocked object?

Edit: Not a duplicate because I'm trying to use it on a "when" and the linked question (and other resources I've found) are using ArgumentCaptor and ArgumentMatcher on "verify" and "assert". I'm thinking I can't actually do what I'm trying and will try out another way. Of course, I'm willing to be shown otherwise.

like image 231
eflat Avatar asked Mar 03 '17 19:03

eflat


People also ask

How can specify the mock Behaviour of an object?

When you create a mock, you create an associated behavior object that controls mock behavior. Use this object to define mock method and property behavior (stub). For more information on creating a mock, see Create Mock Object.

Does Mockito verify use equals?

Mockito verifies argument values in natural java style: by using an equals() method.

What can I use instead of Mockito matchers?

Since Mockito any(Class) and anyInt family matchers perform a type check, thus they won't match null arguments. Instead use the isNull matcher.

What is when thenReturn in Mockito?

In Mockito, you can specify what to return when a method is called. That makes unit testing easier because you don't have to change existing classes. Mockito supports two ways to do it: when-thenReturn and doReturn-when . In most cases, when-thenReturn is used and has better readability.


2 Answers

Reopening as requested, but the solution (use an ArgumentMatcher) is identical to the one in the linked answer. Naturally, you can't use an ArgumentCaptor when stubbing, but everything else is the same.

class OfficeWithId implements ArgumentMatcher<Office> {
  long id;

  OfficeWithId(long id) {
    this.id = id;
  }

  @Override public boolean matches(Office office) {
    return office.id == id;
  }

  @Override public String toString() {
    return "[Office with id " + id + "]";
  }
}

when(client.callApi(anyString(), argThat(new IsOfficeWithId(123L)))
    .thenReturn(responseOne);

Because ArgumentMatcher has a single method, you can even make it a lambda in Java 8:

when(client.callApi(anyString(), argThat(office -> office.id == 123L))
    .thenReturn(responseOne);

If you're already using Hamcrest, you can adapt a Hamcrest matcher using MockitoHamcrest.argThat, or use the built-in hasPropertyWithValue:

when(client.callApi(
         anyString(),
         MockitoHamcrest.argThat(hasPropertyWithValue("id", 123L))))
    .thenReturn(responseOne);
like image 176
Jeff Bowman Avatar answered Sep 28 '22 04:09

Jeff Bowman


I ended up going with "eq". This was ok in this case because the objects are pretty simple. First I created an object that is the same as what I expect to get back.

Office officeExpected = new Office();
officeExpected.setId(22L);

Then my 'when' statement becomes:

when(client.callApi(anyString(), eq(officeExpected))).thenReturn(responseOne);

This allows me to have better checking than "isA(Office.class)".

like image 34
eflat Avatar answered Sep 28 '22 04:09

eflat