我使用Mockito为JUnit编写了一个工作测试,并试图使其适应TestNG,但奇怪的是使用TestNG只有一个测试可以工作。
我认为它在某种程度上与模拟的重置有关,但我已经尝试调用Mockito。重置并使用BeforeMethod和BeforeClass以及不同的组合,但仍然只能通过一个测试。
我需要做什么才能让测试生效?
@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());
}
第二个测试似乎总是在断言内容类型未设置或预期结果错误时失败。
似乎第一次测试的反应在第二次测试中被评估了,所以显然是错误的!
我知道控制器和服务按预期工作,使用jUnit运行的完全相同的测试实际上工作正常。
只有当我执行以下操作时,我才能正确执行测试:
@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());
}
这意味着我需要为每个测试方法添加一个这些重置方法,然后我需要一个似乎不正确的每个测试方法组。
这些框架的行为有所不同:
@Test
s对于Mockito,您需要在每个测试方法之前初始化模拟,以便状态不会在TestNG中的两个@Test
之间共享:
@BeforeMethod
public void init() {
MockitoAnnotations.initMocks(this);
}
对于JUnit,它可以开箱即用,因为第二个@Test
有自己的字段和自己的模拟。
我不确定这个答案是否适合提问者的问题,因为模拟没有列出。但是我想重申安迪在接受的答案中的一个评论,它帮助我解决了同样的问题。这里有一些更多的细节和一个例子:
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;
}
}
MockitosMockitoAnnotations. initMocks(this)
只会重新初始化mock,因为Mockito.set(a)
只会重置mock。问题是被测试的类,它用@InjectMocks
进行了注释。这个类,这里命名为B
,不会再次初始化。它在第一次测试中使用A
的mock进行初始化,A
的mock被重新初始化,但B
仍然包含A
的第一个版本。
解决方案是在任何可能的位置(@Aftermethod
或initMocks
之前)手动重置被测类,使用b=null
。然后Mockito还重新iniziation了被测类B
。
您还可以使用MockitoTestNGListener,它类似于JUnit
MockitoJUnitRunner
或MockitoExency
。
代码示例:
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() {
// ...
}
}