We need to download the Mockito binary to start working with Mockito. You can download the Mockito jar from http://mockito.org/.
As of December 2014, the latest Mockito version is v2.0.2-beta.
The following section configures Eclipse projects to use Mockito.
To add Mockito JAR files as a project dependency, perform the following steps:
MockitoOverview
.This section provides examples of mock objects with a stock quote simulation program. The program observes the market trend and performs the following actions:
The important domain objects in this program are Stock
, MarketWatcher
, Portfolio
, and StockBroker
.
The Stock
class represents real-world stocks. A Stock
object can have properties such as symbol
, company name
, and price
.
The MarketWatcher
object observes the market trend and returns the current stock price. A real-world MarketWatcher
object needs to connect to the Internet to download the stock quote.
The Portfolio
object represents a stock portfolio such stock count and price details. It provides APIs to get the average stock price and methods to buy and sell stocks. Suppose you bought a Facebook share for $75, and the next day, you bought one more Facebook share for $85. So, on the second day, you have two Facebook shares, with the average share price equal to $80.
Here is a screenshot of the Eclipse project. This project can be downloaded from the Packt Publishing website.
The following is the StockBroker
class. It works together with the MarketWatcher
and Portfolio
classes. The perform()
method accepts a portfolio and a stock, gets the current market price of the stock, and compares the current price with the average stock price. If the current stock price goes up 10 percent, then it sells 10 stocks. Otherwise, it buys a stock:
public class StockBroker { private final static BigDecimal LIMIT = new BigDecimal("0.10"); private final MarketWatcher market; public StockBroker(MarketWatcher market) { this.market = market; } public void perform(Portfolio portfolio,Stock stock) { Stock liveStock = market.getQuote(stock.getSymbol()); BigDecimal avgPrice = portfolio.getAvgPrice(stock); BigDecimal priceGained = liveStock.getPrice().subtract(avgPrice); BigDecimal percentGain = priceGained.divide(avgPrice); if(percentGain.compareTo(LIMIT) > 0) { portfolio.sell(stock, 10); }else if(percentGain.compareTo(LIMIT) < 0){ portfolio.buy(stock); } } }
The Portfolio
class reads the average stock price from the database, and the MarketWatcher
class connects to the Internet to get the latest stock price. Therefore, if we need to write a unit test for the broker program, the test will need a database and an Internet connection. The test will interact with external entities, and we can call it an integration test rather than a unit test. If our unit tests interact with the real database and Internet connection, then chances of test failure will increase, as the database state might not be the same across all test runs, and each Internet call to get the stock price might return different values. Therefore asserting a constant value may result in assertion failure; for example, we assert a stock price of $100 in our test but the actual market price goes down to $90, or our test thinks that a portfolio has 10 stocks in the database but some other user adds 20 more shares using a different thread. That's why unit tests mock external dependencies and set a constant value as the expectation, so the preceding example will lead to this: all the time, the portfolio will return 10 as the number of stocks, or the current stock price will always be returned as $100.
In the following section, we'll mock external dependencies using Mockito and execute the test in isolation. Therefore, the test will invoke methods on proxy dependency objects and be self-governing, and thus it will be executed quickly.
The org.mockito.Mockito
class defines a static method mock()
to create mock objects. The following code snippet creates mock objects using the mock
method:
import org.mockito.Mockito; public class StockBrokerTest { MarketWatcher marketWatcher = Mockito.mock(MarketWatcher.class); Portfolio portfolio = Mockito.mock(Portfolio.class); }
Instead of directly calling the Mockito.mock()
method, we can use the static import feature of Java. The following code snippet simplifies mock creation using static import:
import static org.mockito.Mockito.mock; public class StockBrokerTest { MarketWatcher marketWatcher = mock(MarketWatcher.class); Portfolio portfolio = mock(Portfolio.class); }
The alternative is to annotate the class member variables with the @Mock
annotation. The following code snippet uses this annotation:
import org.mockito.Mock; public class StockBrokerTest { @Mock MarketWatcher marketWatcher; @Mock Portfolio portfolio; }
To create mocks using the @Mock
annotation, we need to initialize the mocks before test execution, so use MockitoAnnotations.initMocks(this)
before using the mocks, or use MockitoJUnitRunner
as a JUnit runner.
This example uses MockitoAnnotations
:
import static org.junit.Assert.assertEquals;
import org.mockito.MockitoAnnotations;
public class StockBrokerTest {
@Mock
MarketWatcher marketWatcher;
@Mock
Portfolio portfolio;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void sanity() throws Exception {
assertNotNull(marketWatcher);
assertNotNull(portfolio);
}
}
The following example uses the MockitoJUnitRunner
JUnit runner:
import org.mockito.runners.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class StockBrokerTest { @Mock MarketWatcher marketWatcher; @Mock Portfolio portfolio; @Test public void sanity() throws Exception { assertNotNull(marketWatcher); assertNotNull(portfolio); } }
A few things to remember
Mockito cannot mock or spy on Java constructs such as final classes and methods, static methods, enums, private methods, the equals()
and hashCode()
methods, primitive types, and anonymous classes.
But the good news is that PowerMockito (an extension of the Mockito framework) API allows us to overcome the limitations of Mockito. It lets us mock static and private methods. You can also set expectations on new invocations for local or anonymous classes, private member classes, and inner classes but as per the design, you should not opt for mocking private or static properties because it violates the encapsulation. Instead, you should refactor the offending code to make it testable.
Now, to cross-check the information of a final class that Mockito cannot mock, just modify the Portfolio
class and make it a final class. Then rerun the test. It will fail because the class is final.
The following screenshot shows the output of the JUnit test run:
Stubbing a method means setting up an expectation on a method invocation or simulating the behavior of the method. Mock objects are basically proxy objects, and they imitate the behavior of real objects. We can stub a method on a mock object to redefine the behavior of the method. In other words, we can return a specific value or throw a specific exception when the method is called on the mocked object. If we don't stub a method of a mock object, the mock object returns the default values such as false
for the Boolean return type, null
for the object return type, 0
for the integer or long return type, and so on.
Mockito allows stubbing to return a specific value when a specific method is called. The Mockito.when()
method identifies a method that needs to be stubbed, and the thenReturn()
method returns a specific value.
The when
static method is defined in the Mockito class. Here is the process of importing the when
method in our test class:
import static org.mockito.Mockito.when;
The following example stubs the getQuote(String symbol)
method of MarketWatcher
and returns a specific Stock
object:
import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class StockBrokerTest { @Mock MarketWatcher marketWatcher; @Mock Portfolio portfolio; @Test public void marketWatcher_Returns_current_stock_status() { Stock uvsityCorp = new Stock("UV", "Uvsity Corporation", new BigDecimal("100.00")); when(marketWatcher.getQuote(anyString())). thenReturn(uvsityCorp); assertNotNull(marketWatcher.getQuote("UV")); }
The preceding test method creates a stock object and stubs the getQuote
method of marketWatcher
to return the stock. Note that we passed anyString()
to the getQuote
method, and anyString
represents any string value such as "UV
", which we passed in the next line (marketWatcher.getQuote("UV")
). Therefore, whenever the getQuote
method will be called on the marketWatcher
proxy, the stock object will be returned.
The when()
method represents the trigger for the time to stub.
The following Mockito methods represent the course of action of the trigger:
thenReturn(value to be returned)
: This returns a specific value.thenThrow(throwable to be thrown)
: This throws a specific exception.thenAnswer(Answer answer)
: Unlike returning a specific value, some logic is executed and an action is taken from that logic; for example, some value is computed and returned. Answer
is an interface.thenCallRealMethod()
: This calls the real method on the object. The real method doesn't return any default value. It performs the actual logic, but if it needs to invoke any method that is stubbed, then the stubbed value is passed to the real method; for example, the foo()
method calls bar()
, but bar()
is stubbed to return a value 10
, so foo()
will get 10
.The following test code stubs the portfolio
and marketWatcher
methods:
import com.packt.trading.dto.Stock; import static org.junit.Assert.assertNotNull; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class StockBrokerTest { @Mock MarketWatcher marketWatcher; @Mock Portfolio portfolio; StockBroker broker; @Before public void setUp() { broker = new StockBroker(marketWatcher); } @Test public void when_ten_percent_gain_then_the_stock_is_sold() { //Portfolio's getAvgPrice is stubbed to return $10.00 when(portfolio.getAvgPrice(isA(Stock.class))). thenReturn(new BigDecimal("10.00")); //A stock object is created with current price $11.20 Stock aCorp = new Stock("A", "A Corp", new BigDecimal("11.20")); //getQuote method is stubbed to return the stock when(marketWatcher.getQuote(anyString())).thenReturn( aCorp); //perform method is called, as the stock price increases // by 12% the broker should sell the stocks broker.perform(portfolio, aCorp); //verifying that the broker sold the stocks verify(portfolio).sell(aCorp,10); }
The stubbed getAvgPrice()
method returns $10.00
, and the stubbed getQuote
method returns a stock of A Corp
. The stock is configured to return the current stock price as $11.20
. As the current stock price ($11.20
) is 12 percent more than the average stock price ($10
), broker
will sell 10 A Corp
stocks to book profit.
We already know that the if we don't stub a method on a mock object, then that method returns a default value, but for the void methods, there is nothing to be returned, so no action is taken. In our case, the broker logic invokes the sell
method on the portfolio object, but the sell
method is a void method, so the sell
method is auto-stubbed and it doesn't connect to the database to update the portfolio status. It simply dumps the call.
The perform
method is a void method, so it doesn't return any response saying whether it sold some units or not. So how would we check the logic that 10 stocks were sold? We use Mockito.verify
.
The verify()
method is a static method. It is used to verify the method invocation. If we verify a method call on a mock object but the method is not invoked by the code logic, then the verify()
method raises an exception to indicate that there is something wrong in the code logic. In the preceding example we verified that 10 stocks were sold, but if the code logic doesn't call the sell
method due to some bug in logic and our test verifies the call in test, it signifies that the code is buggy.
An overloaded version of verify()
takes org.mockito.internal.verification.Times
as an argument. Times
takes the wantedNumberOfInvocations
integer argument.
When we pass 0
to Times
, it means that the stubbed method has not been invoked in the testing path, but if the method is invoked once, then the verify
method raises an exception. If we pass a negative number to the Times
constructor, then it throws MockitoException - org.mockito.exceptions.base.MockitoException
, and shows the Negative value is not allowed here error message.
The following methods can be used in combination with verify
:
times(int wantedNumberOfInvocations)
: This signifies that the stubbed method was invoked exactly wantedNumberOfInvocations
times. If the method invocation count doesn't match, then the test fails.never()
: This is equivalent to times
(0
). It signifies that the method wasn't invoked at all.atLeastOnce()
: This signifies that the stubbed method was invoked at least once. It doesn't throw an error if the method is invoked multiple times, but fails if the method is not invoked.atLeast(int minNumberOfInvocations)
: This signifies that the stubbed method was invoked minNumberOfInvocations
or more times. It doesn't throw an error if the stubbed method is invoked more than minNumberOfInvocations
times but fails if the stubbed method is invoked less than minNumberOfInvocations
times.atMost(int maxNumberOfInvocations)
: This signifies that the stubbed method was invoked maxNumberOfInvocations
times. It raises an exception if the method is called more than minNumberOfInvocations
times and works fine if the method is never invoked or invoked less than the maximum count.only()
: This is the only method called on a mock. It fails if any other method is called on the mock object. In our example, if we use verify(portfolio, only()).sell(aCorp,10);
, the test will fail with following output:The test fails when, portfolio.getAvgPrice(stock)
is called (in line number 15).
timeout(int millis)
: This interacts in a specified time range.The verifyZeroInteractions(object... mocks)
method takes an array of mock objects and verifies that no methods were called on the mocks. This is important to check the logic branching. Suppose we have two sets of classes, one to send e-mails, and one to generate the mail printout to be sent over the general mail. During code execution, it should either send an e-mail or print a mail. For the e-mail path, we can verify that no methods were called on the mail printout classes.
The following test demonstrates the verifyZeroInteractions
method and directly passes the two mock objects to it. Since no methods are invoked on the mock objects, the test passes:
@Test public void verify_zero_interaction() { verifyZeroInteractions(marketWatcher,portfolio); }
The verifyNoMoreInteractions(Object... mocks)
method checks whether any of the given mocks has any unverified interaction. We can use this method after verifying a mock method to ensure that nothing else was invoked in the mock.
The following test code demonstrates the verifyNoMoreInteractions
method:
@Test public void verify_no_more_interaction() { Stock noStock = null; portfolio.getAvgPrice(noStock); portfolio.sell(null, 0); verify(portfolio).getAvgPrice(eq(noStock)); //this will fail as the sell method was invoked verifyNoMoreInteractions(portfolio); }
Here is a screenshot showing the JUnit output of the preceding code:
When a piece of code throws a business exception due to violations of some core business logic, then the program should handle the exception instead of halting (for the errors such as Out Of Memory or disk failure, it should definitely halt). In our unit tests, we should consider exceptional conditions such as the code requesting to sell 10 stocks and the portfolio containing only five stocks. Mockito provides methods to throw exceptions during testing.
Mockito defines an action method called thenThrow(Throwable)
. This method throws a specific exception when a trigger occurs or a stubbed method is called.
The getAvgPrice
method scans the database to fetch the average stock price. Suppose the database is unavailable for upgrade or some other reason, and you invoked the method. Then the getAvgPrice
will throw an exception, but it is we who should handle the exception and show a proper meaningful error message to the user. We'll use Mockito's API to throw an exception from the getAvgPrice
method:
@Test(expected = IllegalStateException.class) public void throwsException() throws Exception { when(portfolio.getAvgPrice(isA(Stock.class))).thenThrow( new IllegalStateException("Database down")); portfolio.getAvgPrice(new Stock(null, null, null)); }
We stubbed the getAvgPrice
method of portfolio
to throw an exception.
The following is the syntax to throw an exception from a void method:
doThrow(exception).when(mock).voidmethod(arguments);
The buy
method portfolio is a void method, so we'll stub it to throw an exception:
@Test(expected = IllegalStateException.class)
public void throwsException_void_methods() throws Exception {
doThrow(new IllegalStateException()).
when(portfolio).buy(isA(Stock.class));
portfolio.buy(new Stock(null, null, null));
}
To learn advanced Mockito topics such as Answers
, ArgumentCaptor
, matchers, and so on, read the following books:
3.137.188.201