我使用Mockito为JUnit编写了一个工作测试并尝试使其适用于TestNG,但奇怪的是使用TestNG只有一个测试可以工作。
我认为它在某种程度上与重置模拟相关,但我已经尝试调用Mockito.reset并使用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());
}
这意味着我需要为每种测试方法添加其中一种重置方法,然后我需要一组每种测试方法看起来不正确。
答案 0 :(得分:7)
这些框架的行为有所不同:
@Test
s之间共享对于Mockito,您需要在每个测试方法之前初始化模拟,以便在TestNG中的两个@Test
之间不共享状态:
@BeforeMethod
public void init() {
MockitoAnnotations.initMocks(this);
}
对于JUnit,它开箱即用,因为第二个@Test
有自己的字段和自己的模拟。
答案 1 :(得分:2)
我不确定这个答案是否适合提问者的问题,因为没有列出模拟。但我想在接受的答案中重申 andy 的一条评论,它帮助我解决了同样的问题。以下是更多详细信息和示例:
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)
只重新初始化模拟,因为 Mockito.reset(a)
只重置模拟。问题在于被测类,它用 @InjectMocks
注释。这个名为 B
的类不会再次初始化。它在第一次测试时使用 A
的模拟进行初始化,A
的模拟被重新初始化,但 B
仍然包含 A
的第一个版本。
解决方案是在任何可能的位置使用 b = null
手动重置被测类(@AfterMethod
oder 在 initMocks
之前)。然后 Mockito 还重新初始化了被测类 B
。
答案 2 :(得分:0)
您还可以使用MockitoTestNGListener,它类似于JUnit
MockitoJUnitRunner
或MockitoExtension
。
代码示例:
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() {
// ...
}
}