Mockito

Mockito is one of the most popular mocking framework for java. For me, it is frequently used in daily unit test . I would like to note down some basic usages.

Unit Test and Mocking

We do need the unit test to test our method, our interface, our class, to see whether it performs correctly, especially for methods with complicated business logic. When testing an object which has dependencies on other complex objects, you do not want to create real objects for the unit test. Here comes the mocking that mimics the behavior of real objects.

Basic Mockito

Mockito three phrases:

  1. Mock away external dependencies and insert the mocks into the code under test
  2. Execute the code under test
  3. Validate that the code executed correctly

Here is an example I would like to use. Suppose I have a StockService.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Stock {
private String symbol;
private Double quotePrice;

public String getSymbol() {
return symbol;
}

public void setSymbol(String symbol) {
this.symbol = symbol;
}

public Double getQuotePrice() {
return quotePrice;
}

public void setQuotePrice(Double quotePrice) {
this.quotePrice = quotePrice;
}
}
1
2
3
public interface AutoComplete {
public String getSymbol(String companyName) throws TimeoutException;
}
1
2
3
public interface Quotes {
public Double getQuotes (String symbol) throws TimeoutException;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class StockService {
private AutoComplete autoComplete;
private Quotes quotes;
private List<Stock> portfolio;

public StockService(AutoComplete autoComplete, Quotes quotes) {
this.autoComplete = autoComplete;
this.quotes = quotes;
portfolio = new ArrayList<>();
}

public List<Stock> getPortfolio() {
return portfolio;
}

public void setPortfolio(List<Stock> portfolio) {
this.portfolio = portfolio;
}

public Double getStockPrice(String searchInput) {
try {
String symbol = autoComplete.getSymbol(searchInput);
return quotes.getQuotes(symbol);
} catch (NullPointerException e) {
return 0.0;
} catch (TimeoutException e) {
return 0.0;
}
}

public void addStockToPortfolio(Stock stock) {
portfolio.add(stock);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class StockServiceTest {
@Mock
private Quotes quotes;
@Mock
private AutoComplete autoComplete;

private StockService stockService;

@BeforeMethod
public void setup() {
MockitoAnnotations.initMocks(this);
stockService = new StockService(autoComplete, quotes);
}

@Test
public void testStockServiceWithValidInput() throws TimeoutException {
String input = "Apple";
when(autoComplete.getSymbol(input)).thenReturn("AAPL");
when(quotes.getQuotes("AAPL")).thenReturn(164.00);
double applePrice = stockService.getStockPrice(input);
assertEquals(applePrice, 164.00);
}

@Test
public void testStockServiceWithInvalidInput() throws TimeoutException {
when(autoComplete.getSymbol(anyString())).thenReturn(null);
assertEquals(stockService.getStockPrice("foo"), 0.0);
}

@Test
void testStockServiceWithTimeout() throws TimeoutException {
String input = "apple";
when(autoComplete.getSymbol(input)).thenThrow(new TimeoutException("Time out"));
assertEquals(stockService.getStockPrice(input), 0.0);
}
}

Use @Mock to create mock objects. Add MockitoAnnotations.initMocks(this) to populate the annotated fields.
Utilize when(...).thenReturn(...) or when(…).thenThrow(…) to imitate methods.
Verify the results via verify() / assert() to check logic.

Spy & ArgumentCaptor

@Spy or spy() means you want to spying on the real objects which can be associated with “partial mocking” concept. Take real into consideration. There exists difference in using when(…).thenReturn(…) and doReturn(...).when(...)

1
2
3
4
5
6
7
8
List list = new LinkedList();
List spy = spy(list);

//Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");

//You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);

At the same time, we can make use of ArgumentCaptor to verifies argument values. It is recommended to use ArgumentCaptor with verification but not with stubbing. In some situations though, it is helpful to assert on certain arguments after the actual verification. Suppose that we want to test whether the stock is added to stockList via addStockToPortfolio() , argumentCaptor could be a way to captor and test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test void testPortfolio() {
List<Stock> stockList = mock(List.class);
ArgumentCaptor<Stock> stockArgument = ArgumentCaptor.forClass(Stock.class);
stockService.setPortfolio(stockList);

Stock apple = new Stock();
apple.setSymbol("AAPL");
apple.setQuotePrice(164.00);

stockService.addStockToPortfolio(apple);
verify(stockList).add(stockArgument.capture());

assertEquals(stockArgument.getValue().getSymbol(), "AAPL");
}

With Guava

Besides to setter to access to private field and mock its method, we can use Guava’ s @VisibleForTesting to help us. Here is one example. Suppose I remove autocomplete and quote services from constructor.

public StockService() {
    portfolio = new ArrayList<>();
    autoComplete = ..;
    quotes = ..;
}

@VisibleForTesting
public StockService(AutoComplete autoComplete, Quotes quotes) {
    portfolio = new ArrayList<>();
    this.autoComplete = autoComplete;
    this.quotes = quotes;
}

Reference

https://www.vogella.com/tutorials/Mockito/article.html
https://static.javadoc.io/org.mockito/mockito-core/2.25.1/org/mockito/Mockito.html#13

To be continued.. 😄