【问题标题】:Using Mockito with TestNG将 Mockito 与 TestNG 一起使用
【发布时间】:2016-06-02 12:17:06
【问题描述】:

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

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

【问题讨论】:

  • 您使用什么库进行断言 (Result expectedResult = new Result())?
  • 你在每个方法之后都重置了模拟,但你没有对mocMvc做任何事情。这会影响你的测试吗?您能否通过将@BeforeClass 更改为@BeforeMethod 来验证这一点
  • 嗨,Eugen,我试过玩,但没有任何组合奏效。我将用我设法开始工作的内容更新我的帖子,但这意味着很多代码重复。
  • 库是springs MockMvcResultMatchers

标签: spring unit-testing mockito testng


【解决方案1】:

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

  • JUnit 为其每个测试方法创建一个新的类实例。这意味着这些字段不会在测试之间共享。
  • 但是 TestNG 只创建一个对象,因此字段中的状态在 @Tests 之间共享

对于 Mockito,您需要在每个测试方法之前初始化模拟,以便在 TestNG 中的两个 @Tests 之间不会共享状态:

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

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

【讨论】:

  • 我已经尝试过了,但它不起作用,调用的结果以错误的顺序返回。因此,如果我的 add 方法预期结果为 5,而我的减法方法预期结果为 10,则有时我的 add 测试将​​失败,并出现断言错误,即它收到 10 并预期为 5。
  • 你确定你使用@BeforeMethod,而不是@BeforeClass
  • 我尝试了 BeforeMethod 和 BeforeClass。测试是对控制器进行真正的调用并模拟服务响应,所以我看不出结果是如何混淆的。我能够让测试工作的唯一方法是使用组并给每个方法一个组,然后在之前的组注释中重置,但我会再尝试一次 BeforeMethod 并很快回来,因为我正在调用 Mockito .reset 在 AfterMethod 注释中。
  • 结果:失败的测试:CalculatorControllerTestNGTest>AbstractTestNGSpringContextTests.run:175->addFunctionTest:97 JSON 路径“$.result”预期: 但:是 CalculatorControllerTestNGTest>AbstractTestNGSpringContextTests.run:175 ->subtractFunctionTest:118 内容类型未设置测试运行:4,失败:2,错误:0,跳过:0 [INFO] ---------------------- -------------------------------------------------- [信息] 构建失败
  • 对我来说,它与@BeforeMethod 一起工作,并将用@InjectMocks 注释的实例设置为null 调用initMocks() 之前。见 //见code.google.com/archive/p/mockito/issues/304
【解决方案2】:

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


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 的第一个版本。

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

【讨论】:

    【解决方案3】:

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

    代码示例:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-08
      • 1970-01-01
      • 2020-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多