Creating mocks with a different default answer
If not changed by the custom configuration, Mockito sets the mock ReturnsEmptyValues
answer by default (for details on that answer, please check the subsequent There's more... section). Note that in Chapter 4, Stubbing Behavior of Mocks, where we deal with stubbing of particular methods, you can learn how to stub particular methods with a custom answer.
In the following recipe, we will see how to change the default answer to a custom or a predefined one.
Getting ready
It is more than probable that you will not ever need to create a custom answer for Mockito—there are plenty of them already bundled in Mockito and there is no need to reinvent the wheel. Why would you want to create a custom answer anyway? Let's take a look at a couple of possible answers to that question:
- It is possible that for debugging purposes, you would like to log the arguments that were passed to the stubbed method
- You could also want to perform some more complex logic on the passed argument rather than just return some fixed value
- You want to stub asynchronous methods that have callbacks (you provide those callbacks in the custom
Answer
implementation) - Believe me, you don't want to capture the arguments and check them! Check Chapter 6, Verifying Test Doubles, for more information
If you thought it over and still want to create a custom answer, please check if there isn't one already existing in Mockito.
In the provided Mockito API, you can find the following answers in the AdditionalAnswers
class (check the Javadoc of that class for examples):
returnsFirstArg
: This answer will return the first argument of the invocationreturnsSecondArg
: This answer returns the second argument of the invocationreturnsLastArg
: This answer returns the last argument of the invocationreturnsArgAt
: This answer returns the argument of the invocation provided at the given indexdelegatesTo
: This answer delegates all methods to the delegate (you will in fact call the delegate's method if the method hasn't already been stubbed)returnsElementsOf
: This answer returns the elements of the provided collection
There is also the Mockito class itself that contains some Answer
interface implementations (they are static final fields, thus their names are in uppercase). These are RETURNS_DEFAULT
, RETURNS_SMART_NULLS
, RETURNS_MOCKS
, RETURNS_DEEP_STUBS
, and CALLS_REAL_METHODS
; they all delegate to answers described in more depth in the There's more... section.
If you feel that none of these answers satisfy your requirements, you have to create your own implementation of the Answer
interface. The next part of this recipe will show how to pass the answer to the created mock. Our system under test is a class that calculates a mean value of tax factors retrieved through a web service. Have a look at the following code:
public class MeanTaxFactorCalculator { private final TaxService taxService; public MeanTaxFactorCalculator(TaxService taxService) { this.taxService = taxService; } public double calculateMeanTaxFactorFor(Person person) { double currentTaxFactor = taxService.getCurrentTaxFactorFor(person); double anotherTaxFactor = taxService.getCurrentTaxFactorFor(person); return (currentTaxFactor + anotherTaxFactor) / 2; } }
How to do it...
To set a different default answer without annotations, you have to use the overloaded Mockito.mock(Class<T> classToMock, Answer defaultAnswer)
static method.
The following snippet shows an example of a test that uses the ThrowsExceptionClass
answer set on a mock as its default answer:
public class MeanTaxFactorCalculatorTest { TaxService taxService = mock(TaxService.class, new ThrowsExceptionClass(IllegalStateException.class)); MeanTaxFactorCalculator systemUnderTest = new MeanTaxFactorCalculator(taxService); @Test public void should_throw_exception_when_calculating_mean_tax_factor() { // expect try { systemUnderTest.calculateMeanTaxFactorFor(new Person()); fail("Should throw exception"); } catch (IllegalStateException exception) {} } }
How it works...
Mockito takes the passed answer type argument and creates MockitoSettings
from it as follows:
public static <T> T mock(Class<T> classToMock, Answer defaultAnswer) { return mock(classToMock, withSettings().defaultAnswer(defaultAnswer)); }
In this way, the default mock's answer is changed to the custom one. In this way, if not previously stubbed, all of the mock's methods will, by default, execute the logic from the passed Answer
implementation.
There's more...
Here is the list of additional, interesting Mockito Answer
implementations together with a short description (mind you, they are part of the Mockito internals, so I'm presenting them for you to understand what happens under the hood while using Mockito. Be cautious when using them):
Returns
: It always returns the object passed in the constructor of thisAnswer
implementation.ReturnsEmptyValues
: When creating a mock, all of its methods are stubbed as follows based on the method's return type:- For primitives: It returns default Java-appropriate primitive values (0 for integer, false for boolean, and so on)
- For primitive wrappers: It returns the same values as for primitives
- For most commonly used collection types: It returns an empty collection
- For the
toString()
method: It returns the mock's name - For
Comparable.compareTo(T other)
: It returns 1 (meaning that the objects are not equal to each other) - For anything else: It returns null
ReturnsMoreEmptyValues
: This implementation extends theReturnsEmptyValues
functionality with the following additional default return types:- For arrays: It returns an empty array
- For strings: It returns an empty string ("")
- Returns an empty array for methods that return arrays
- Returns an empty string ("") for methods returning strings
ReturnsSmartNulls
: If aNullPointerException
gets thrown on mock, Mockito catches it and rethrowsSmartNullPointerException
with additional helpful messages. Additionally, it acts likeReturnsMoreEmptyValues
.DoesNothing
: This method always returns null for objects (non-primitive types) and default values for primitives.CallsRealMethods
: This method creates a partial mock by default, unstubbed methods delegate to real implementations.ReturnsArgumentAt
: This method returns an argument at a specified position of an array (for -1, it returns its last element).ReturnsElementsOf
: This method keeps returning subsequent elements of the collection that is passed in the constructor. Once it arrives at the tail of the collection, it will always return that value.ReturnsDeepStubs
: This method allows easy nested mock creation and method chain stubbing. Check Chapter 8, Refactoring with Mockito, for usage examples and suggestions why you should not use it.ThrowsExceptionClass
: This method throws the exception passed as the argument to the constructor ofAnswer
for each method. Mockito will instantiate the exception for you.ThrowsException
: This method throws an instantiated exception passed to the constructor ofAnswer
.ReturnsMocks
: First, this method tries to return values such as the ones defined inReturnsMoreEmptyValues
and, if that fails, it tries to return a mock. Eventually, if this attempt fails at either of them,ReturnsMocks
returns null. Please think twice before using this answer (or use it only to refactor some legacy code), since it clearly means that something is wrong with your design.Note
Another interesting feature is that if you create a class called
MockitoConfiguration
that implementsIMockitoConfiguration
or extends theDefaultMockitoConfiguration
class in theorg.mockito.configuration
package. You can then set a global answer for all your mocks. The following snippet shows what a Mockito configuration class should look like in order to change the default answer of any mock toReturnsSmartNulls
:public class MockitoConfiguration extends DefaultMockitoConfiguration { public Answer<Object> getDefaultAnswer() { return new ReturnsSmartNulls(); } }
See also
- Refer to the Mockito AdditonalAnswers API from http://docs.mockito.googlecode.com/hg/1.9.5/org/mockito/AdditionalAnswers.html
- Refer to the Google testing blog on when and how to use Mockito Answer from http://googletesting.blogspot.com/2014/03/whenhow-to-use-mockito-answer.html