Creating mocks with custom configuration
Even though in the majority of cases you will not need the feature discussed in the preceding recipe, sometimes you may want your mock to satisfy some additional prerequisites. Thanks to Mockito's Mockito.withSettings
fluent interface, you can easily set up your custom MockitoSettings
object that you can pass to the Mockito.mock
method that will create your mock. When you check out the Javadoc of MockitoSettings
, you will see a note that you shouldn't use that class too often. That's good advice, because you should make it a practice to write your code and tests in such a way that it is either of high quality or low complexity. In other words, in real life, you shouldn't need to configure your mocks in such a complex way.
Getting ready
Let's take a look at the following MockitoSettings
interface methods:
extraInterfaces(...)
: This method specifies which additional interfaces the mock should implement. It can be quite useful when dealing with legacy code. Check out Chapter 8, Refactoring with Mockito (you shouldn't need to ever have to use it in well-written code).name(...)
: By calling this method, you define a custom mock name. It can be useful when debugging your test since the provided name will be omnipresent in the verification errors.spiedInstance(...)
: This method specifies the instance to spy on (refer to Chapter 3, Creating Spies and Partial Mocks, for more details on spies).defaultAnswer(...)
: This method is used by the mock if not defined otherwise by explicit method stubbing (in other words, if you don't stub a method here, you define what should happen when you execute it).serializable()
: This method makes the mock serializable; however, generally speaking, you shouldn't have the need to call this method in well-designed code.verboseLogging()
: This method logs method invocations on the mock; it might be useful for debugging to verify which interaction was unnecessary on the mock.invocationListeners(...)
: If you want to perform some additional debugging actions on your mocks each time a method gets executed on it, you have to implement your own listener and register it on the mock via this method.
In the following code, our system under test is a class that collects a person's IRS address and formats it properly based on his or her country:
public class TaxFactorInformationProvider { private final TaxService taxService; public TaxFactorInformationProvider(TaxService taxService) { this.taxService = taxService; } public String formatIrsAddress(Person person) { String irsAddress = taxService.getInternalRevenueServiceAddress(person.getCountryName()); return "IRS:[" + irsAddress + "]"; } }
Let's now write a test for the system under test that will check whether the address will be properly formatted if the IRS address would be an empty string. We have to create a stub of TaxService
and stub it's behavior (we don't want it to send any real requests).
How to do it...
To customize your mock's configuration via the MockitoSettings
interface, you have to perform the following steps:
- Create the
mock(Class<T> classToMock, MockSettings mockSettings)
method. - Pass the
MockSettings
object via the staticwithSettings()
method as the second method's parameter.
Now let's take a look at the test written for JUnit. For the TestNG configuration, refer to Chapter 1, Getting Started with Mockito (I'm using the BDDMockito.given(...)
and AssertJ's BDDAssertions.then(...)
static methods. Check out Chapter 7, Verifying Behavior with Object Matchers, on how to work with AssertJ or how to do the same with Hamcrest's assertThat(...)
).
public class MeanTaxFactorCalculatorTest { static final double TAX_FACTOR = 10; TaxService taxService = mock(TaxService.class, withSettings().serializable()); MeanTaxFactorCalculator systemUnderTest = new MeanTaxFactorCalculator(taxService); @Test public void should_calculate_mean_tax_factor() { // given given(taxService.getCurrentTaxFactorFor(any(Person.class))).willReturn(TAX_FACTOR); // when double meanTaxFactor = systemUnderTest.calculateMeanTaxFactorFor(new Person()); // then then(meanTaxFactor).isEqualTo(TAX_FACTOR); then(taxService).isInstanceOf(Serializable.class); } }
How it works...
What Mockito does internally is that it calls the MockitoCore
class that is the point of entry for creating mocks. Then, a mock is created using the provided MockitoSettings
object.
There's more...
If you are using annotations to create your mock, you also have some possibilities of customization. Take a look at the following @Mock
annotation's additional parameters:
answer
: This parameter is one of the predefined answers present in theAnswers
enumname
: This parameter is the name of the mockextraInterfaces
: This parameter specifies which additional interfaces the mock should implement
The following is an example of a @Mock
annotated field containing all of the previously mentioned parameters (the probability that you will use more than one parameter, if any, is very small):
@Mock(answer = Answers.RETURNS_SMART_NULLS, extraInterfaces = {Iterable.class, Serializable.class}, name = "Custom tax service mock") TaxService taxService;
See also
- Refer to the Mockito documentation on MockitoSettings class from http://docs.mockito.googlecode.com/hg/1.9.5/org/mockito/MockSettings.html