A dive into Mockito – 2


Part 2 – Argument Matchers and Stubbing Void Methods

  • Using Argument Matchers
  • A simple use of any() matcher
  • Writing Custom Argument Matchers
  • Stubbing void methods

Full Series


Using Argument Matchers

Mockito argument matchers can be used to specify the method arguments for stubbing. If the method has arguments but you really don’t care what gets passed or cannot predict it, argument matchers can be used.

Argument Matchers provide us a lot of flexibility in stubbing.

Argument Matchers use the equals() method for comparisons.



A simple use of any() matcher

Let us assume we have an EmailService that is trying to save an email ID using an EmailManager. This means that the save() method of the EmailService calls the save() method of the EmailManager, which in turn saves the email to the database. A simple unit test for the save() method of the EmailService can test whether the save() on the Manager was called.

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

public class EmailServiceTest {
	@Test
	public void testSaveEmail() {
		EmailManager manager = Mockito.mock(EmailManager.class);
		EmailService service = new EmailService(manager);

		service.save("abc@xyz.com");

		Mockito.verify(manager).save(Mockito.anyString());
	}
}

Note the use of the argument matcher in line 12:

Mockito.verify(manager).save(Mockito.anyString());

We used the matcher because, we really do not care what parameter was passed on the save().

The generic any() matcher:

Mockito provides a matcher that matches any Object. Some valid variants of the above are:

Mockito.verify(manager).save(Mockito.any());
Mockito.verify(manager).save(Mockito.any(String.class));

The cast from Object to String is required in the first line, the lack of which will cause compilation error.

The second line shown above is most useful when we need to match custom classes we create in our application.
Assuming save() method saves a Person object, we would write:

Mockito.verify(manager).save(Mockito.any(Person.class));

While using argument matchers in stubbing, all arguments of a method must be matchers.

If our save method also takes in an integer, this line would throw error:

Mockito.verify(manager).save(12, Mockito.any(Person.class));

To fix the above scenario, we can write:

Mockito.verify(manager).save(Mockito.eq(12), Mockito.any(Person.class));

Some common Argument Matchers

ARGUMENT MATCHERSDESCRIPTION
any() or any(Class clazz)Any object (or object of a given class) or null
anyString()
anyInt()
anyFloat()
anyDouble()
anyBoolean()
anyByte()
anyChar()
anyObject()
anyCollection()
anyList()
anyMap()
anySet()

Any object of given type or null
eqDefault Matcher. Compares using equals() method
sameObject argument that is the same as the given value. Compares using ==
refEqObject argument that is reflection-equal to the given value. This Matcher can be used when equals() is not implemented on compared objects. Matcher uses Java reflection API to compare fields of wanted and actual objects.
isNull
isNotNull
Argument is null/not null
contains(String substring)
matches(String regex)
endsWith(String suffix)
startsWith(String prefix)
String-specific argument matchers

Writing Custom Argument Matchers

Consider this scenario. We have the following classes:

  • Person – A class with two variables – name, email id
  • PersonService – A service class that creates a Person object and calls savePerson() method on the manager
  • PersonManager – The manager class that needs to be mocked

We need to write test case for personLogic() method in PersonService

PersonService.java:

public class PersonService {
	private final PersonManager manager;

	public PersonService(PersonManager manager) {
		this.manager = manager;
	}

	public void personLogic() {
		Person person = new Person("Karthik", "abc@xyz.com");
		manager.savePerson(person);
	}
}

The below test will fail:

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

public class PersonServiceTest {
	@Test
	public void testPersonLogic() {
		PersonManager manager = Mockito.mock(PersonManager.class);
		PersonService service = new PersonService(manager);

		service.personLogic();

		Person verifyPerson = new Person("Karthik", "abc@xyz.com");
		Mockito.verify(manager).savePerson(verifyPerson);
	}
}

Reason: The expected object, with reference verifyPerson is entirely different from the actual object, and the default equals() comparison which argument matchers use, fails.

Use Custom Argument Matcher

In this scenario, using custom argument matchers come in handy.

Lines 12 and 13 above can be replaced with this:

Mockito.verify(manager).savePerson(
				Mockito.argThat(new ArgumentMatcher() {

					@Override
					public boolean matches(Object argument) {
						Person person = (Person) argument;
						return person.getName().equals("Karthik")
								&& person.getEmail().equals("abc@xyz.com") ? true
								: false;
					}
				}));

Alternate Solution – 1

Use the refEq matcher to compare the fields of the objects in hand:

Person verifyPerson = new Person("Karthik", "abc@xyz.com");
Mockito.verify(manager).savePerson(Mockito.refEq(verifyPerson));

Alternate Solution – 2

Override the equals() method in Person class to compare objects.


Stubbing void methods

We face a lot of scenarios in our applications where we need to stub void methods. With void methods, stubbing is slightly different. We cannot use void methods in the when() call.

The alternative syntax is:

Mockito.doReturn(result).when(mock).method();

We can also test exception handling. How would my code handle if an exception is thrown by void methods

Mockito.doThrow(new RuntimeException()).when(mock).setAttribute(Mockito.anyString());

We can also set the behaviour of a void method to do nothing when called. This is not possible for non-void methods:

Mockito.doNothing().when(mock).method();

Why when() does not work for void methods:

Take a look at the syntax of when():

when(mock.method())

Notice that the method is called inside brackets. Compiler does not like void method inside brackets!!

The two ‘when()’ are different syntax.

Notice that the when() for a non-void method stubbing takes in a methodCall as parameter, whereas the when() in void method stubbing takes in a mock object.

STUBBING WITH MOCKITO
USAGE
doPrimarily used for stubbing void methods
doCallRealMethod().when(mock).method();
doNothing().when(mock).method();
doThrow(Throwable... throwables).when(mock).method();
doReturn(T value).when(mock).method();
doAnswer(Answer answer).when(mock).method();

Future articles in the series:

  • Part 3 – Partial Mocks using Mockito and Limitations of Mockito
  • Part 4 – Some complex examples and common mistakes in using Mockito

Share this article
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

One thought on “A dive into Mockito – 2”

  1. This is a superb article. Thanks a lot for taking the time to describe all of this out for us. It’s a great guide!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>