I took a working test written for JUnit using Mockito and tried to adapt it to work with TestNG but oddly using TestNG only one test will work.
I think it is somehow related to the resetting of the mocks but I have played around with trying to call Mockito.reset and using BeforeMethod and BeforeClass and different combinations but still can only get one test to pass.
What I need to do to get the test to work?
@BeforeClass
public void setUp() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(calculatorController).build();
}
@AfterMethod
public void reset() {
Mockito.reset(calculatorService);
}
@Test
public void addFunctionTest() throws Exception {
Assert.assertNotNull(calculatorController);
Result expectedResult = new Result();
expectedResult.setResult(10);
when(calculatorService.add(anyInt(), anyInt())).thenReturn(expectedResult);
mockMvc.perform(get("/calculator/add").accept(MediaType.APPLICATION_JSON_VALUE)
.param("val1", "100")
.param("val2", "100"))
.andExpect(content().contentType("application/json"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.result", equalTo(10)));
verify(calculatorService, times(1)).add(anyInt(), anyInt());
}
@Test
public void subtractFunctionTest() throws Exception {
Assert.assertNotNull(calculatorController);
Result expectedResult = new Result();
expectedResult.setResult(90);
when(calculatorService.subtract(anyInt(), anyInt())).thenReturn(expectedResult);
mockMvc.perform(get("/calculator/subtract").accept(MediaType.APPLICATION_JSON_VALUE)
.param("val1", "100")
.param("val2", "10"))
.andExpect(content().contentType("application/json"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.result", equalTo(90)));
verify(calculatorService, times(1)).subtract(anyInt(), anyInt());
}
The second test always seems to fail on assertions that either content type is not set or the expected result is wrong.
It seems like the response for the first test is somehow being evaluated in the second test and so is obviously wrong!
I know the controller and service work as expected and the exact same tests running with jUnit actually work ok.
I have managed to get the tests to perform properly only when I do the following:
@BeforeGroups("subtract")
public void reset() {
Mockito.reset(calculatorService);
mockMvc = MockMvcBuilders.standaloneSetup(calculatorController).build();
}
@Test(groups = "subtract")
public void subtractFunctionTest() throws Exception {
System.out.println("***** IN METHOD *****");
Assert.assertNotNull(calculatorController);
Result expectedResult = new Result();
expectedResult.setResult(90);
when(calculatorService.subtract(anyInt(), anyInt())).thenReturn(expectedResult);
//Perform HTTP Get for the homepage
mockMvc.perform(get("/calculator/subtract").accept(MediaType.APPLICATION_JSON_VALUE)
.param("val1", "100")
.param("val2", "10"))
.andExpect(content().contentType("application/json"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.result", equalTo(90)));
//Verify that the service method was only called one time
verify(calculatorService, times(1)).subtract(anyInt(), anyInt());
}
This means I need to add one of these reset methods for each test method though and I then need a group per test method which doesnt seem correct.
Mockito is a java based mocking framework, used in conjunction with other testing frameworks such as JUnit and TestNG. It internally uses Java Reflection API and allows to create objects of a service.
Mockito uses the BDDMockito class that is available in the org. mockito package. It develops a test in BDD style. The BDD style of writing texts uses the //given //when //then comments as the primary part of the test body.
Mockito is a mocking framework, JAVA-based library that is used for effective unit testing of JAVA applications.
There is a difference in the behaviour of these frameworks:
@Test
sFor Mockito you need to init mocks before every test method so that the state is not shared between two @Test
s in TestNG:
@BeforeMethod
public void init() {
MockitoAnnotations.initMocks(this);
}
For JUnit it works out of box because 2nd @Test
has its own fields and its own mocks.
I'm not sure, if this answer fits to the questioners problem, because the mocks are not listed. But I'd like to re-state one comment from andy in the accepted answer, which helped me out on the same problem. Here are some more details and an example:
public class B {
private A a;
B (A a) {
this.a = a
}
// ...
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class MyTest {
@Mock
A a;
@InjectMocks
B B;
@BeforeMethod
public void init() {
MockitoAnnotations.initMocks(this);
}
@Test
void test1() {
// ...
// b.toString();
// b.getA().toString();
// a.toString();
}
@Test
void test2() {
// ...
// b.toString();
// b.getA().toString();
// a.toString();
}
@AfterMethod
public void reset()
{
// Solution:
b = null;
}
}
Mockitos MockitoAnnotations.initMocks(this)
only re-initializes mocks, as Mockito.reset(a)
only resets mocks. The problem is the class under test, which is annotated with @InjectMocks
. This class, here named B
, is not initialized again. It is initialized for the first test with a mock of A
, the mock of A
is re-initialized but B
still contains the first version of A
.
The solution is to reset the class under test manually with b = null
at any plausible place (@AfterMethod
or before initMocks
). Then Mockito also re-inizialized the class under test B
.
You can also use MockitoTestNGListener it is similar to JUnit
MockitoJUnitRunner
or MockitoExtension
.
Example of code:
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import java.util.Map;
@Listeners(MockitoTestNGListener.class)
public class MyTest {
@Mock
Map map;
@InjectMocks
SomeType someType;
@Test
void test() {
// ...
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With