Mockito Cookbook
上QQ阅读APP看书,第一时间看更新

Getting started with Mockito for TestNG

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

TestNG is a unit testing framework for Java that was created, as the author defines it on the tool's website (refer to the See also section for the link), out of frustration for some JUnit deficiencies. TestNG was inspired by both JUnit and TestNG and aims at covering the whole scope of testing—from unit, through functional, integration, end-to-end tests, and so on. However, the JUnit library was initially created for unit testing only.

The main differences between JUnit and TestNG are as follows:

  • The TestNG author disliked JUnit's approach of having to define some methods as static to be executed before the test class logic gets executed (for example, the @BeforeClass annotated methods)—that's why in TestNG you don't have to define these methods as static
  • TestNG has more annotations related to method execution before single tests, suites, and test groups
  • TestNG annotations are more descriptive in terms of what they do, for example, the JUnit's @Before versus TestNG's @BeforeMethod

Mockito in Version 1.9.5 doesn't provide any out-of-the-box solution to integrate with TestNG in a simple way, but there is a special Mockito subproject for TestNG (refer to the See also section for the URL) that should be part one of the subsequent Mockito releases. In the following recipe, we will take a look at how to profit from that code and that very elegant solution.

Getting ready

When you take a look at Mockito's TestNG subproject on the Mockito GitHub repository, you will find that there are three classes in the org.mockito.testng package, as follows:

  • MockitoAfterTestNGMethod
  • MockitoBeforeTestNGMethod
  • MockitoTestNGListener

Unfortunately, until this project eventually gets released, you have to just copy and paste those classes to your codebase.

How to do it...

To integrate TestNG and Mockito, perform the following steps:

  1. Copy the MockitoAfterTestNGMethod, MockitoBeforeTestNGMethod, and MockitoTestNGListener classes to your codebase from Mockito's TestNG subproject.
  2. Annotate your test class with @Listeners(MockitoTestNGListener.class).
  3. Annotate the test fields with the @Mock or @Spy annotation to have either a mock or spy object instantiated.
  4. Annotate the test fields with the @InjectMocks annotation to first instantiate the @InjectMock annotated field and inject all the @Mock or @Spy annotated fields into it (if applicable).
  5. Annotate the test fields with the @Captor annotation to make Mockito instantiate an argument captor (check Chapter 6, Verifying Test Doubles, for more details).

Now let's take a look at this snippet that, using TestNG, checks whether the mean tax factor value has been calculated properly (remember that I'm using the BDDMockito.given(...) and AssertJ's BDDAssertions.then(...) static methods—refer to Chapter 7, Verifying Behavior with Object Matchers, on how to work with Hamcrest assertThat(...) method):

@Listeners(MockitoTestNGListener.class)
public class MeanTaxFactorCalculatorTestNgTest {

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

}

How it works...

TestNG allows you to register custom listeners (your listener class has to implement the IInvokedMethodListener interface). Once you do this, the logic inside the implemented methods will be executed before and after every configuration, and test methods get called. Mockito provides you with a listener whose responsibilities are as follows:

  • Initialize mocks annotated with the @Mock annotation (it is done only once)
  • Validate the usage of Mockito after each test method

Note

Remember that with TestNG all mocks are reset (or initialized if it hasn't already been done) before any TestNG method!

See also