将Mockito与TestNG结合使用



我使用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());
}

这意味着我需要为每个测试方法添加一个重置方法,然后我需要每个测试方法一组,这似乎不正确。

这些框架的行为有所不同:

JUnit为它的每个测试方法创建一个新的类实例。这意味着测试之间不共享字段
  • 但是TestNG只创建一个对象,因此字段中的状态在@Test之间共享
  • 对于Mockito,您需要在每个测试方法之前初始化mock,这样状态就不会在TestNG:中的两个@Test之间共享

    @BeforeMethod
    public void init() {
    MockitoAnnotations.initMocks(this);
    }
    

    对于JUnit来说,它是开箱即用的,因为第二个@Test有自己的字段和mock。

    我不确定这个答案是否适合提问者的问题,因为没有列出模拟。但我想在接受的答案中重新陈述安迪的一条评论,这条评论帮助我解决了同样的问题。以下是更多细节和示例:


    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.reset(a)仅重置mock。问题是测试中的类,它用@InjectMocks进行了注释。这个名为B的类不会再次初始化。它在第一次测试中用A的mock初始化,A的mock被重新初始化,但B仍然包含A的第一个版本。

    解决方案是在任何可能的位置(@AfterMethodinitMocks之前)使用b = null手动重置测试中的类。然后Mockito还将测试B下的类重新初始化。

    您也可以使用MockitoTestNGListener,它类似于JUnitMockitoJUnitRunnerMockitoExtension

    代码示例:

    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() {
    // ...
    }
    }
    

    相关内容

    • 没有找到相关文章

    最新更新