Exploring Mockito

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.

Configuring Mockito

To add Mockito JAR files as a project dependency, perform the following steps:

  1. Unzip the Mockito JAR files into a folder.
  2. Open Eclipse.
  3. In Eclipse, create a Java project named MockitoOverview.
  4. Right-click on the project. A pop-up menu will appear. Expand the Build Path menu and click on the Configure Build Path menu item. It will open a wizard. Go to the Libraries tab in the Java build path.
  5. Click on the Add External JARs... button and browse to the Mockito folder.
  6. Select all JAR files and click on OK.

Mocking in action

This section provides examples of mock objects with a stock quote simulation program. The program observes the market trend and performs the following actions:

  • Buying new stocks
  • Selling existing stocks

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.

Mocking in action

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.

Mocking objects

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);
  }
}

Tip

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:

Mocking objects

Stubbing methods

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.

Verifying in depth

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:
    Verifying in depth

    The test fails when, portfolio.getAvgPrice(stock) is called (in line number 15).

  • timeout(int millis): This interacts in a specified time range.

Verifying zero and no more interactions

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:

Verifying zero and no more interactions

Throwing exceptions

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:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.188.201