Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
MOCKITO COOKBOOK

You're reading from   MOCKITO COOKBOOK Over 65 recipes to get you up and running with unit testing using Mockito.

Arrow left icon
Product type Paperback
Published in Jun 2014
Publisher
ISBN-13 9781783982745
Length 284 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Marcin Grzejszczak Marcin Grzejszczak
Author Profile Icon Marcin Grzejszczak
Marcin Grzejszczak
Arrow right icon
View More author details
Toc

Table of Contents (12) Chapters Close

Preface 1. Getting Started with Mockito FREE CHAPTER 2. Creating Mocks 3. Creating Spies and Partial Mocks 4. Stubbing Behavior of Mocks 5. Stubbing Behavior of Spies 6. Verifying Test Doubles 7. Verifying Behavior with Object Matchers 8. Refactoring with Mockito 9. Integration Testing with Mockito and DI Frameworks 10. Mocking Libraries Comparison Index

Getting started with Mockito for JUnit

Before going into details regarding Mockito and JUnit integration, it is worth mentioning a few words about JUnit.

JUnit is a testing framework (an implementation of the xUnit framework) that allows you to create repeatable tests in a very readable manner. In fact, JUnit is a port of Smalltalk's SUnit (both the frameworks were originally implemented by Kent Beck). What is important in terms of JUnit and Mockito integration is that under the hood, JUnit uses a test runner to run its tests (from xUnit—test runner is a program that executes the test logic and reports the test results).

Mockito has its own test runner implementation that allows you to reduce boilerplate in order to create test doubles (mocks and spies) and to inject them (either via constructors, setters, or reflection) into the defined object. What's more, you can easily create argument captors. All of this is feasible by means of proper annotations as follows:

  • @Mock: This is used for mock creation
  • @Spy: This is used to create a spy instance
  • @InjectMocks: This is used to instantiate the @InjectMock annotated field and inject all the @Mock or @Spy annotated fields into it (if applicable)
  • @Captor: This is used to create an argument captor

By default, you should profit from Mockito's annotations to make your code look neat and to reduce the boilerplate code in your application.

Getting ready

In order to add JUnit to your classpath, if you are using a dependency manager that connects to the Maven Central Repository, then you can get your dependencies as follows (examples for Maven and Gradle):

To add JUnit in Maven, use the following code:

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.11</version>
  <scope>test</scope>
</dependency>

To add JUnit in Gradle, use the following code:

testCompile('junit:junit:4.11')

If you are not using any of the dependency managers, you have to download the following jars:

  • junit.jar
  • hamcrest-core.jar

Add the downloaded files to your classpath manually (you can download the jars from https://github.com/junit-team/junit/wiki/Download-and-Install).

For this recipe, our system under test will be a MeanTaxFactorCalculator class that will call an external service, TaxService, to get the current tax factor for the current user. It's a tax factor and not tax as such, since for simplicity, we will not be using BigDecimals but doubles, and I'd never suggest using doubles to anything related to money, as follows:

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 use Mockito's annotations, you have to perform the following steps:

  1. Annotate your test with the @RunWith(MockitoJUnitRunner.class).
  2. Annotate the test fields with the @Mock or @Spy annotation to have either a mock or spy object instantiated.
  3. Annotate the test fields with the @InjectMocks annotation to first instantiate the @InjectMock annotated field and then inject all the @Mock or @Spy annotated fields into it (if applicable).
  4. Annotate the test fields with the @Captor annotation to make Mockito instantiate an argument captor (refer to Chapter 6, Verifying Test Doubles, for more details).

The following snippet shows the JUnit and Mockito integration in a test class that verifies the SUT's behavior (remember that I'm using BDDMockito.given(...) and AssertJ's BDDAssertions.then(...) static methods; refer to Chapter 7, Verifying Behavior with Object Matchers, for how to work with AssertJ or how to do the same with Hamcrest's assertThat(...) method):

@RunWith(MockitoJUnitRunner.class)
public class MeanTaxFactorCalculatorTest {

    static final double TAX_FACTOR = 10;

    @Mock TaxService taxService;

    @InjectMocks MeanTaxFactorCalculator systemUnderTest;

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

}

Note

To profit from Mockito's annotations using JUnit, you just have to annotate your test class with @RunWith(MockitoJUnitRunner.class).

How it works...

The Mockito test runner will adapt its strategy depending on the version of JUnit. If there exists a org.junit.runners.BlockJUnit4ClassRunner class, it means that the codebase is using at least JUnit in Version 4.5.What eventually happens is that the MockitoAnnotations.initMocks(...) method is executed for the given test, which initializes all the Mockito annotations (for more information, check the subsequent There's more… section).

There's more...

You may have a situation where your test class has already been annotated with a @RunWith annotation and, seemingly, you may not profit from Mockito's annotations. In order to achieve this, you have to call the MockitoAnnotations.initMocks method manually in the @Before annotated method of your test, as shown in the following code:

public class MeanTaxFactorCalculatorTest {

    static final double TAX_FACTOR = 10;

    @Mock TaxService taxService;

    @InjectMocks MeanTaxFactorCalculator systemUnderTest;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void should_calculate_mean_tax_factor() {
        // given
        given(taxService.getCurrentTaxFactorFor(Mockito.any(Person.class))).willReturn(TAX_FACTOR);

        // when
        double meanTaxFactor = systemUnderTest.calculateMeanTaxFactorFor(new Person());

        // then
        then(meanTaxFactor).isEqualTo(TAX_FACTOR);
    }

}

Note

To use Mockito's annotations without a JUnit test runner, you have to call the MockitoAnnotations.initMocks method and pass the test class as its parameter.

Mockito checks whether the user has overridden the global configuration of AnnotationEngine and, if this is not the case, the InjectingAnnotationEngine implementation is used to process annotations in tests. What is done internally is that the test class fields are scanned for annotations and proper test doubles are initialized and injected into the @InjectMocks annotated object (either by a constructor, property setter, or field injection, in that precise order).

Note

You have to remember several factors related to the automatic injection of test doubles as follows:

  • If Mockito is not able to inject test doubles into the @InjectMocks annotated fields through either of the strategies, it won't report failure—the test will continue as if nothing happened (and most likely, you will get NullPointerException).
  • For constructor injection, if arguments cannot be found, then null is passed
  • For constructor injection, if nonmockable types are required in the constructor, then the constructor injection won't take place.
  • For other injection strategies, if you have properties with the same type (or same erasure) and if Mockito matches mock names with a field/property name, it will inject that mock properly. Otherwise, the injection won't take place.
  • For other injection strategies, if the @InjectMocks annotated object wasn't previously initialized, then Mockito will instantiate the aforementioned object using a no-arg constructor if applicable.

See also

You have been reading a chapter from
MOCKITO COOKBOOK
Published in: Jun 2014
Publisher:
ISBN-13: 9781783982745
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image