Mockito

Mockito void Method Example

In Mockito Hello World Example, we have learnt how to stub a non-void method that returns something. Sometimes we may also need to stub a void method which is what I am going to show in this article.

Before I start with my example, a bit about my setup:

 

1. Mockito Void Method Example

The example I have chosen is about a dish that a customer is going to taste. Dish object represents the dish. It has a void eat() method which the customer object will call when served with the dish. If the dish is not the one customer is expecting then it will throw WrongDishException.

In the next few sections, I will show you different ways of stubbing the void method eat() to change its behavior.

The usual way to stub a non-void method is:

when(dish.eat()).thenReturn("some value");

But note that eat() doesn’t return anything so naturally we won’t be able to use the above style of API.

We can stub a void method to throw an exception using doThrow(). Other than that we can also make use of doNothing() and doAnswer() APIs.

Customer:

package com.javacodegeeks.mockito;

public class Customer {
	public void eat(Dish dish) throws WrongDishException {
		try {
			System.out.println("Taste the food");
			dish.eat();
			System.out.println("Ate the food");
		} catch (WrongDishException e) {
			System.out.println("Wrong dish!");
			throw e;
		} catch (NotSuchATastyException e) {
			System.out.println("Not very tasty");
			throw e;
		}		
	}
}

Dish:

package com.javacodegeeks.mockito;

public interface Dish {
	void eat() throws WrongDishException;
}

2. Stub void method Using deprecated API stubVoid

Originally, stubVoid() was used for stubbing void methods with exceptions. For example, in test testEatUsingStubVoid(), we stub eat() to simply return without throwing an exception, we can do it using stubVoid() and toReturn().

stubVoid(dish).toReturn().on().eat();

Now when we call customer.eat(dish), it doesn’t throw any exception.

But note that stubVoid() is deprecated so we won’t use it any more. doThrow() and doReturn() replaces stubVoid() because of improved readability and consistency with the family of doAnswer() methods.

MockitoVoidExample:

package com.javacodegeeks.mockito;

import static org.mockito.Mockito.*;
import static org.testng.Assert.*;

import org.mockito.InOrder;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class MockitoVoidExample {
	private Customer customer;
	private Dish dish;
	
	@BeforeMethod
	public void setupMock() {
		customer = new Customer();
		dish = mock(Dish.class);
	}
	
	@Test
	public void testEatUsingStubVoid() throws WrongDishException {
		System.out.println("Train dish to not throw WrongDishException using stubVoid");
		stubVoid(dish).toReturn().on().eat();
		customer.eat(dish);
		System.out.println("Finished the dish, no exception thrown");
	}	
}

Output:

Train dish to not throw WrongDishException using stubVoid
Taste the food
Ate the food
Finished the dish, no exception thrown
PASSED: testEatUsingStubVoid

3. Stub void method Using toReturn

In test testEatUsingDoNothing, we replace stubVoid() with doNothing() and when().

doNothing().when(dish).eat();

MockitoVoidExample:

package com.javacodegeeks.mockito;

import static org.mockito.Mockito.*;

import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class MockitoVoidExample {
	private Customer customer;
	private Dish dish;
	
	@BeforeMethod
	public void setupMock() {
		customer = new Customer();
		dish = mock(Dish.class);
	}
	
	@Test
	public void testEatUsingStubVoid() throws WrongDishException {
		System.out.println("Train dish to not throw WrongDishException using stubVoid");
		stubVoid(dish).toReturn().on().eat();
		customer.eat(dish);
		System.out.println("Finished the dish, no exception thrown");
	}
	
	@Test
	public void testEatUsingDoNothing() throws WrongDishException {
		System.out.println("Train dish to not throw WrongDishException using doNothing");
		doNothing().when(dish).eat();
		customer.eat(dish);
		System.out.println("Finished the dish, no exception thrown");
	}
}

Output:

Train dish to not throw WrongDishException using doNothing
Taste the food
Ate the food
Finished the dish, no exception thrown
PASSED: testEatUsingDoNothing

4. Stub void method Using doThrow

In evaluateFood(), we stub method dish.eat() to throw NotSoTastyException using doThrow() and when() combination.

doThrow(NotSuchATastyException.class).when(dish).eat();

MockitoVoidExample:

package com.javacodegeeks.mockito;

import static org.mockito.Mockito.*;

import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class MockitoVoidExample {
	private Customer customer;
	private Dish dish;
	
	@BeforeMethod
	public void setupMock() {
		customer = new Customer();
		dish = mock(Dish.class);
		when(dish.getSpice()).thenReturn(null);
	}
	
	@Test
	public void testEatUsingStubVoid() throws WrongDishException {
		System.out.println("Train dish to not throw WrongDishException using stubVoid");
		stubVoid(dish).toReturn().on().eat();
		customer.eat(dish);
		System.out.println("Finished the dish, no exception thrown");
	}
	
	@Test
	public void testEatUsingDoNothing() throws WrongDishException {
		System.out.println("Train dish to not throw WrongDishException using doNothing");
		doNothing().when(dish).eat();
		customer.eat(dish);
		System.out.println("Finished the dish, no exception thrown");
	}
	
	@Test(expectedExceptions=NotSoTastyException.class)
	public void evaluateFood() throws WrongDishException {
		doThrow(NotSoTastyException.class).when(dish).eat();
		customer.eat(dish);
		System.out.println("Won't reach here");
	}	
}

Output:

Taste the food
Not very tasty
PASSED: evaluateFood

5. Stub void method Using doAnswer

Suppose we want to custom behavior a method’s behavior based on the arguments passed then we can use doAnswer() API.

Answer interface specifies an action that is executed when you interact with the mock’s method. We can customize the behavior based on the mock’s method name or the method arguments which is passed to it. In case of non-void methods, you can even make the answer to customize the method’s return value.

In test ifSpiceThrowException(), the customer orders for a spicy dish. If the dish is of medium spice then customer.eat(dish) will return quietly. If the dish is too spicy then the overloaded eat(spice) method is going to throw a RuntimeException.

SpiceAnswer implements Answer and based on the degree of spice, it will either throw a RuntimeException or return a value.

We stub the custom behavior using doAnswer() and when() APIs.

doAnswer(new SpiceAnswer()).when(dish).eat(spicy);

Dish:

package com.javacodegeeks.mockito;

public interface Dish {
	void eat() throws WrongDishException;
	void eat(String spicy) throws WrongDishException;
	String getSpice();
}

MockitoVoidExample:

package com.javacodegeeks.mockito;

import static org.mockito.Mockito.*;

import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class MockitoVoidExample {
	private Customer customer;
	private Dish dish;
	
	@BeforeMethod
	public void setupMock() {
		customer = new Customer();
		dish = mock(Dish.class);
		when(dish.getSpice()).thenReturn(null);
	}
	
	@Test
	public void testEatUsingStubVoid() throws WrongDishException {
		System.out.println("Train dish to not throw WrongDishException using stubVoid");
		stubVoid(dish).toReturn().on().eat();
		customer.eat(dish);
		System.out.println("Finished the dish, no exception thrown");
	}
	
	@Test
	public void testEatUsingDoNothing() throws WrongDishException {
		System.out.println("Train dish to not throw WrongDishException using doNothing");
		doNothing().when(dish).eat();
		customer.eat(dish);
		System.out.println("Finished the dish, no exception thrown");
	}
	
	@Test(expectedExceptions=NotSoTastyException.class)
	public void evaluateFood() throws WrongDishException {
		doThrow(NotSoTastyException.class).when(dish).eat();
		customer.eat(dish);
		System.out.println("Won't reach here");
	}	
	
	@Test(expectedExceptions=RuntimeException.class)
	public void ifSpiceThrowException() throws WrongDishException {
		System.out.println("Train dish to not throw NotSoTastyException when called first time and return in subsequent calls");
		String spicy = "spicy";
		when(dish.getSpice()).thenReturn(spicy);		
		doAnswer(new SpiceAnswer()).when(dish).eat(spicy);
		customer.eat(dish);		
		
		spicy = "too spicy";
		when(dish.getSpice()).thenReturn(spicy);		
		doAnswer(new SpiceAnswer()).when(dish).eat(spicy);
		customer.eat(dish);		
	}
	
	private class SpiceAnswer implements Answer {
		@Override
		public String answer(InvocationOnMock invocation) throws Throwable {
			String arg = (String) invocation.getArguments()[0];
			if ("too spicy".equals(arg)) {
				throw new RuntimeException("Spicy dish!");
			}
			return arg;
		}		
	}
}

Output:

Train dish to not throw NotSoTastyException when called first time and return in subsequent calls
Taste the food
Ate the food
Taste the food
PASSED: ifSpiceThrowException

6. Stub void method with consecutive calls

Sometimes we may need to stub a method with different behaviors for each consecutive call of the same method.
In test eatMultipleDishes(), NotSoTastyException is thrown the first time customer.eat(dish) is called. But no exception is thrown in the subsequent calls to customer.eat(dish).

doThrow(NotSoTastyException.class).doNothing().when(dish).eat();

MockitoVoidExample:

package com.javacodegeeks.mockito;

import static org.mockito.Mockito.*;

import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class MockitoVoidExample {
	private Customer customer;
	private Dish dish;
	
	@BeforeMethod
	public void setupMock() {
		customer = new Customer();
		dish = mock(Dish.class);
		when(dish.getSpice()).thenReturn(null);
	}
	
	@Test
	public void testEatUsingStubVoid() throws WrongDishException {
		System.out.println("Train dish to not throw WrongDishException using stubVoid");
		stubVoid(dish).toReturn().on().eat();
		customer.eat(dish);
		System.out.println("Finished the dish, no exception thrown");
	}
	
	@Test
	public void testEatUsingDoNothing() throws WrongDishException {
		System.out.println("Train dish to not throw WrongDishException using doNothing");
		doNothing().when(dish).eat();
		customer.eat(dish);
		System.out.println("Finished the dish, no exception thrown");
	}
	
	@Test(expectedExceptions=NotSoTastyException.class)
	public void evaluateFood() throws WrongDishException {
		doThrow(NotSoTastyException.class).when(dish).eat();
		customer.eat(dish);
		System.out.println("Won't reach here");
	}	
	
	@Test(expectedExceptions=RuntimeException.class)
	public void ifSpiceThrowException() throws WrongDishException {
		System.out.println("Train dish to not throw NotSuchATastyException when called first time and retun in subsquent calls");
		String spicy = "spicy";
		when(dish.getSpice()).thenReturn(spicy);		
		doAnswer(new SpiceAnswer()).when(dish).eat(spicy);
		customer.eat(dish);		
		
		spicy = "too spicy";
		when(dish.getSpice()).thenReturn(spicy);		
		doAnswer(new SpiceAnswer()).when(dish).eat(spicy);
		customer.eat(dish);		
	}
	
	private class SpiceAnswer implements Answer {
		@Override
		public String answer(InvocationOnMock invocation) throws Throwable {
			String arg = (String) invocation.getArguments()[0];
			if ("too spicy".equals(arg)) {
				throw new RuntimeException("Spicy dish!");
			}
			return arg;
		}		
	}
	
	@Test
	public void eatMultipleDishes() throws WrongDishException {
		System.out.println("Train dish to not throw NotSoTastyException when called first time and return in subsequent calls");
		doThrow(NotSoTastyException.class).doNothing().when(dish).eat();
		try {
			customer.eat(dish);
			Assert.fail("allows eating, should have failed with NotSoTastyException");
		} catch(NotSoTastyException e) {
			System.out.println("Coudln't eat the dish, not very tasty");
		}
		customer.eat(dish);
		System.out.println("Finished the dish, no exception thrown");
		customer.eat(dish);
		System.out.println("Finished the dish, no exception thrown");		
	}
}

Output:

Train dish to not throw NotSoTastyException when called first time and return in subsequent calls
Taste the food
Not very tasty
Coudln't eat the dish, not very tasty
Taste the food
Ate the food
Finished the dish, no exception thrown
Taste the food
Ate the food
Finished the dish, no exception thrown
PASSED: eatMultipleDishes

7. Download the Eclipse Project

This was an example of Mockito void Method.

Download
You can download the full source code of this example here: mockitoVoid.zip

Ram Mokkapaty

Ram holds a master's degree in Machine Design from IT B.H.U. His expertise lies in test driven development and re-factoring. He is passionate about open source technologies and actively blogs on various java and open-source technologies like spring. He works as a principal Engineer in the logistics domain.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button