Progressive Mockito

0
122
15 min read

(For more resources related to this topic, see here.)

Drinking Mockito

Download the latest Mockito binary from the following link and add it to the project dependency:

http://code.google.com/p/mockito/downloads/list

As of February 2014, the latest Mockito version is 1.9.5.

Configuring Mockito

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

  1. Extract the JAR files into a folder.
  2. Launch Eclipse.
  3. Create an Eclipse project named Chapter04.
  4. Go to the Libraries tab in the project build path.
  5. Click on the Add External JARs… button and browse to the Mockito JAR folder.
  6. Select all JAR files and click on OK.

We worked with Gradle and Maven and built a project with the JUnit dependency. In this section, we will add Mockito dependencies to our existing projects.

The following code snippet will add a Mockito dependency to a Maven project and download the JAR file from the central Maven repository (http://mvnrepository.com/artifact/org.mockito/mockito-core):

<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>1.9.5</version> <scope>test</scope> </dependency>

The following Gradle script snippet will add a Mockito dependency to a Gradle project:

testCompile 'org.mockito:mockito-core:1.9.5'

Mocking in action

This section demonstrates the mock objects with a stock quote example. In the real world, people invest money on the stock market—they buy and sell stocks. A stock symbol is an abbreviation used to uniquely identify shares of a particular stock on a particular market, such as stocks of Facebook are registered on NASDAQ as FB and stocks of Apple as AAPL.

We will build a stock broker simulation program. The program will watch the market statistics, and depending on the current market data, you can perform any of the following actions:

  • Buy stocks
  • Sell stocks
  • Hold stocks

The domain classes that will be used in the program are Stock, MarketWatcher, Portfolio, and StockBroker.

Stock represents a real-world stock. It has a symbol, company name, and price.

MarketWatcher looks up the stock market and returns the quote for the stock. A real implementation of a market watcher can be implemented from http://www.wikijava.org/wiki/Downloading_stock_market_quotes_from_Yahoo!_finance. Note that the real implementation will connect to the Internet and download the stock quote from a provider.

Portfolio represents a user’s stock data such as the number of stocks and price details. Portfolio exposes APIs for getting the average stock price and buying and selling stocks. Suppose on day one someone buys a share at a price of $10.00, and on day two, the customer buys the same share at a price of $8.00. So, on day two the person has two shares and the average price of the share is $9.00.

The following screenshot represents the Eclipse project structure. You can download the project from the Packt Publishing website and work with the files:

The following code snippet represents the StockBroker class. StockBroker collaborates with the MarketWatcher and Portfolio classes. The perform() method of StockBroker accepts a portfolio and a Stock object:

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

Look at the perform method. It takes a portfolio object and a stock object, calls the getQuote method of MarketWatcher, and passes a stock symbol. Then, it gets the average stock price from portfolio and compares the current market price with the average stock price. If the current stock price is 10 percent greater than the average price, then the StockBroker program sells 10 stocks from Portfolio; however, if the current stock price goes down by 10 percent, then the program buys shares from the market to average out the loss.

Why do we sell 10 stocks? This is just an example and 10 is just a number; this could be anything you want.

StockBroker depends on Portfolio and MarketWatcher; a real implementation of Portfolio should interact with a database, and MarketWatcher needs to connect to the Internet. So, if we write a unit test for the broker, we need to execute the test with a database and an Internet connection. A database connection will take time and Internet connectivity depends on the Internet provider. So, the test execution will depend on external entities and will take a while to finish. This will violate the quick test execution principle. Also, the database state might not be the same across all test runs. This is also applicable for the Internet connection service. Each time the database might return different values, and therefore asserting a specific value in your unit test is very difficult.

We’ll use Mockito to mock the external dependencies and execute the test in isolation. So, the test will no longer be dependent on real external service, and therefore it will be executed quickly.

Mocking objects

A mock can be created with the help of a static mock() method as follows:

import org.mockito.Mockito; public class StockBrokerTest { MarketWatcher marketWatcher = Mockito.mock(MarketWatcher.class); Portfolio portfolio = Mockito.mock(Portfolio.class); }

Otherwise, you can use Java’s static import feature and static import the mock method of the org.mockito.Mockito class as follows:

import static org.mockito.Mockito.mock; public class StockBrokerTest { MarketWatcher marketWatcher = mock(MarketWatcher.class); Portfolio portfolio = mock(Portfolio.class); }

There’s another alternative; you can use the @Mock annotation as follows:

import org.mockito.Mock; public class StockBrokerTest { @Mock MarketWatcher marketWatcher; @Mock Portfolio portfolio; }

However, to work with the @Mock annotation, you are required to call MockitoAnnotations.initMocks( this ) before using the mocks, or use MockitoJUnitRunner as a JUnit runner.

The following code snippet uses MockitoAnnotations to create mocks:

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

Before we deep dive into the Mockito world, there are a few things to remember. Mockito cannot mock or spy the following functions: final classes, final methods, enums, static methods, private methods, the hashCode() and equals() methods, anonymous classes, and primitive types.

PowerMock (an extension of EasyMock) and PowerMockito (an extension of the Mockito framework) allows you to mock static and private methods; even PowerMockito allows you to set expectations on new invocations for private member classes, inner classes, and local or anonymous classes. However, as per the design, you should not opt for mocking private/static properties—it violates the encapsulation. Instead, you should refactor the offending code to make it testable.

Change the Portfolio class, create the final class, and rerun the test; the test will fail as the Portfolio class is final, and Mockito cannot mock a final class.

The following screenshot shows the JUnit output:

Stubbing methods

We read about stubs in ,Test Doubles. The stubbing process defines the behavior of a mock method such as the value to be returned or the exception to be thrown when the method is invoked.

The Mockito framework supports stubbing and allows us to return a given value when a specific method is called. This can be done using Mockito.when() along with thenReturn ().

The following is the syntax of importing when:

import static org.mockito.Mockito.when;

The following code snippet stubs the getQuote(String symbol) method of MarcketWatcher 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")); } }

A uvsityCorp stock object is created with a stock price of $100.00 and the getQuote method is stubbed to return uvsityCorp whenever the getQuote method is called. Note that anyString() is passed to the getQuote method, which means whenever the getQuote method will be called with any String value, the uvsityCorp object will be returned.

The when() method represents the trigger, that is, when to stub.

The following methods are used to represent what to do when the trigger is triggered:

  • thenReturn(x): This returns the x value.
  • thenThrow(x): This throws an x exception.
  • thenAnswer(Answer answer): Unlike returning a hardcoded value, a dynamic user-defined logic is executed. It’s more like for fake test doubles, Answer is an interface.
  • thenCallRealMethod(): This method calls the real method on the mock object.

The following code snippet stubs the external dependencies and creates a test for the StockBroker class:

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 test method name is when_ten_percent_gain_then_the_stock_is_sold; a test name should explain the intention of the test. We use underscores to make the test name readable. We will use the when_<<something happens>>_then_<<the action is taken>> convention for the tests.

In the preceding test example, the getAvgPrice() method of portfolio is stubbed to return $10.00, then the getQuote method is stubbed to return a hardcoded stock object with a current stock price of $11.20. The broker logic should sell the stock as the stock price goes up by 12 percent.

The portfolio object is a mock object. So, unless we stub a method, by default, all the methods of portfolio are autostubbed to return a default value, and for the void methods, no action is performed. The sell method is a void method; so, instead of connecting to a database to update the stock count, the autostub will do nothing.

However, how will we test whether the sell method was invoked? We use Mockito.verify.

The verify() method is a static method, which is used to verify the method invocation. If the method is not invoked, or the argument doesn’t match, then the verify method will raise an error to indicate that the code logic has issues.

Verifying the method invocation

To verify a redundant method invocation, or to verify whether a stubbed method was not called but was important from the test perspective, we should manually verify the invocation; for this, we need to use the static verify method.

Why do we use verify?

Mock objects are used to stub external dependencies. We set an expectation, and a mock object returns an expected value. In some conditions, a behavior or method of a mock object should not be invoked, or sometimes, we may need to call the method N (a number) times. The verify method verifies the invocation of mock objects.

Mockito does not automatically verify all stubbed calls.

If a stubbed behavior should not be called but the method is called due to a bug in the code, verify flags the error though we have to verify that manually. The void methods don’t return values, so you cannot assert the returned values. Hence, verify is very handy to test the void methods.

Verifying in depth

The verify() method has an overloaded version that takes Times as an argument. Times is a Mockito framework class of the org.mockito.internal.verification package, and it takes wantedNumberOfInvocations as an integer argument.

If 0 is passed to Times, it infers that the method will not be invoked in the testing path. We can pass 0 to Times(0) to make sure that the sell or buy methods are not invoked. If a negative number is passed to the Times constructor, Mockito throws MockitoException – org.mockito.exceptions.base.MockitoException, and this shows the Negative value is not allowed here error.

The following methods are used in conjunction with verify:

  • times(int wantedNumberOfInvocations): This method is invoked exactly n times; if the method is not invoked wantedNumberOfInvocations times, then the test fails.
  • never(): This method signifies that the stubbed method is never called or you can use times(0) to represent the same scenario. If the stubbed method is invoked at least once, then the test fails.
  • atLeastOnce(): This method is invoked at least once, and it works fine if it is invoked multiple times. However, the operation fails if the method is not invoked.
  • atLeast(int minNumberOfInvocations): This method is called at least n times, and it works fine if the method is invoked more than the minNumberOfInvocations times. However, the operation fails if the method is not called minNumberOfInvocations times.
  • atMost(int maxNumberOfInvocations): This method is called at the most n times. However, the operation fails if the method is called more than minNumberOfInvocations times.
  • only(): The only method called on a mock 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 the following output:

    The test fails in line 15 as portfolio.getAvgPrice(stock) is called.

  • timeout(int millis): This method is interacted in a specified time range.

Verifying zero and no more interactions

The verifyZeroInteractions(Object… mocks) method verifies whether no interactions happened on the given mocks.

The following test code directly calls verifyZeroInteractions and passes the two mock objects. 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 make sure that nothing else was invoked on the mock.

The following test code demonstrates verifyNoMoreInteractions:

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

The following is the JUnit output:

The following are the rationales and examples of argument matchers.

Using argument matcher

ArgumentMatcher is a Hamcrest matcher with a predefined describeTo() method. ArgumentMatcher extends the org.hamcrest.BaseMatcher package. It verifies the indirect inputs into a mocked dependency.

The Matchers.argThat(Matcher) method is used in conjunction with the verify method to verify whether a method is invoked with a specific argument value.

ArgumentMatcher plays a key role in mocking. The following section describes the context of ArgumentMatcher.

Mock objects return expected values, but when they need to return different values for different arguments, argument matcher comes into play. Suppose we have a method that takes a player name as input and returns the total number of runs (a run is a point scored in a cricket match) scored as output. We want to stub it and return 100 for Sachin and 10 for xyz. We have to use argument matcher to stub this.

Mockito returns expected values when a method is stubbed. If the method takes arguments, the argument must match during the execution; for example, the getValue(int someValue) method is stubbed in the following way:

when(mockObject.getValue(1)).thenReturn(expected value);

Here, the getValue method is called with mockObject.getValue(100). Then, the parameter doesn’t match (it is expected that the method will be called with 1, but at runtime, it encounters 100), so the mock object fails to return the expected value. It will return the default value of the return type—if the return type is Boolean, it’ll return false; if the return type is object, then null, and so on.

Mockito verifies argument values in natural Java style by using an equals() method. Sometimes, we use argument matchers when extra flexibility is required.

Mockito provides built-in matchers such as anyInt(), anyDouble(), anyString(), anyList(), and anyCollection().

More built-in matchers and examples of custom argument matchers or Hamcrest matchers can be found at the following link:

http://docs.mockito.googlecode.com/hg/latest/org/mockito/Matchers.html

Examples of other matchers are isA(java.lang.Class<T> clazz), any(java.lang.Class<T> clazz), and eq(T) or eq(primitive value).

The isA argument checks whether the passed object is an instance of the class type passed in the isA argument. The any(T) argument also works in the same way.

Why do we need wildcard matchers?

Wildcard matchers are used to verify the indirect inputs to the mocked dependencies. The following example describes the context.

In the following code snippet, an object is passed to a method and then a request object is created and passed to service. Now, from a test, if we call the someMethod method and service is a mocked object, then from test, we cannot stub callMethod with a specific request as the request object is local to the someMethod:

public void someMethod(Object obj){ Request req = new Request(); req.setValue(obj); Response resp = service.callMethod(req); }

If we are using argument matchers, all arguments have to be provided by matchers.

We’re passing three arguments and all of them are passed using matchers:

verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));

The following example will fail because the first and the third arguments are not passed using matcher:

verify(mock).someMethod(1, anyString(), "third argument");

LEAVE A REPLY

Please enter your comment!
Please enter your name here