1. Introduction
Mockito is a popular Java mocking framework. With it, it’s simple to create mock objects, configure mock behavior, capture method arguments, and verify interactions with mocks.
Now, we’ll focus on specifying mock behavior. We have two ways to do that: the when().thenDoSomething() and the doSomething().when() syntax.
In this short tutorial, we’ll see why we have both of them.
2. when() Method
Let’s consider the following Employee interface:
interface Employee {
String greet();
void work(DayOfWeek day);
}
In our tests, we use a mock of this interface. Let’s say we want to configure the mock’s greet() method to return the string “Hello”. It’s straightforward to do so using Mockito’s when() method:
@Test
void givenNonVoidMethod_callingWhen_shouldConfigureBehavior() {
// given
when(employee.greet()).thenReturn("Hello");
// when
String greeting = employee.greet();
// then
assertThat(greeting, is("Hello"));
}
What happens? The employee object is a mock. When we call any of its methods, Mockito registers that call. With the call of the when() method, Mockito knows that this invocation wasn’t an interaction by the business logic. It was a statement that we want to assign some behavior to the mock object. After that, with one of the thenXxx() methods, we specify the expected behavior.
Until this point, it’s good old mocking. Likewise, we want to configure the work() method to throw an exception, when we call it with an argument of Sunday:
@Test
void givenVoidMethod_callingWhen_wontCompile() {
// given
when(employee.work(DayOfWeek.SUNDAY)).thenThrow(new IAmOnHolidayException());
// when
Executable workCall = () -> employee.work(DayOfWeek.SUNDAY);
// then
assertThrows(IAmOnHolidayException.class, workCall);
}
Unfortunately, this code won’t compile, because in the work(employee.work(…)) call, the work() method has a void return type; hence we cannot wrap it into another method call. Does it mean that we can’t mock void methods? Of course, we can. doXxx methods to the rescue!
3. doXxx() Methods
Let’s see how we can configure the exception throwing with the doThrow() method:
@Test
void givenVoidMethod_callingDoThrow_shouldConfigureBehavior() {
// given
doThrow(new IAmOnHolidayException()).when(employee).work(DayOfWeek.SUNDAY);
// when
Executable workCall = () -> employee.work(DayOfWeek.SUNDAY);
// then
assertThrows(IAmOnHolidayException.class, workCall);
}
This syntax is slightly different than the previous one: we don’t try to wrap a void method call inside another method call. Therefore, this code compiles.
Let’s see what just happened. First, we stated that we want to throw an exception. Next, we called the when() method, and we passed the mock object. After that, we specified which mock interaction’s behavior we want to configure.
Note that this isn’t the same when() method we used before. Also, note that we chained the mock interaction after the invocation of when(). Meanwhile, we defined it inside the parentheses with the first syntax.
Why do we have the first when().thenXxx(), when it isn’t capable of such a common task, as configuring a void invocation? It has multiple advantages to the doXxx().when() syntax.
First, it’s more logical for developers to write and read statements like “when some interaction, then do something” than “do something, when some interaction”.
Second, we can add multiple behaviors to the same interaction with chaining. That’s because when() returns an instance of the class OngoingStubbing
On the other hand, doXxx() methods return a Stubber instance, and Stubber.when(T mock) returns T, so we can specify what kind of method invocation we want to configure. But T is part of our application, for example, Employee in our code snippets. But T won’t return a Mockito class, so we won’t be able to add multiple behaviors with chaining.
4. BDDMockito
BDDMockito uses an alternative syntax to those which we covered. It’s pretty simple: in our mock configurations, we have to replace the keyword “when” to “given” and the keyword “do” to “will“. Other than that, our code remains the same:
@Test
void givenNonVoidMethod_callingGiven_shouldConfigureBehavior() {
// given
given(employee.greet()).willReturn("Hello");
// when
String greeting = employee.greet();
// then
assertThat(greeting, is("Hello"));
}
@Test
void givenVoidMethod_callingWillThrow_shouldConfigureBehavior() {
// given
willThrow(new IAmOnHolidayException()).given(employee).work(DayOfWeek.SUNDAY);
// when
Executable workCall = () -> employee.work(DayOfWeek.SUNDAY);
// then
assertThrows(IAmOnHolidayException.class, workCall);
}
5. Conclusion
We saw the advantages and disadvantages of the configuring a mock object the when().thenXxx() or the doXxx().when() way. Also, we saw how these syntaxes work and why we have both.
As usual, the examples are available over on GitHub.