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:
- Copy the
MockitoAfterTestNGMethod
,MockitoBeforeTestNGMethod
, andMockitoTestNGListener
classes to your codebase from Mockito's TestNG subproject. - Annotate your test class with
@Listeners(MockitoTestNGListener.class)
. - Annotate the test fields with the
@Mock
or@Spy
annotation to have either a mock or spy object instantiated. - 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). - 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
- The TestNG homepage at http://testng.org/doc/index.html
- The Mockito TestNG subproject at https://github.com/mockito/mockito/tree/master/subprojects/testng
- The Getting started with Mockito for JUnit recipe on the
@InjectMocks
analysis