You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JUnit参数化测试中如何让Mock对象返回测试参数?

问题描述

使用JUnit的@ParameterizedTest结合枚举源编写测试时,尝试用枚举构造对象并让Mock方法返回该对象,运行时抛出InvalidUseOfMatchersException异常。

异常信息

org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced or misused argument matcher detected here:  

You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
verify(mock).someMethod(contains("foo"))

初始代码

枚举类

public static enum CodeEnum {
   S1("S1"),
   S2("S2")
}

测试类(枚举源版本)

@RunWith(MockitoJUnitRunner.class)
public class FooTest {
   
   @Mocked
   MockedObject mockedObject;
   
   @InjectMocks
   Foo underTest;

   @ParameterizedTest
   @EnumSource(CodeEnum.class)
   public void test_ParametrizedTest(CodeEnum enumParam) {
      
      Output expectedReturn = Output.builder().code(enumParam).build();
      
      // Given
      when(mockedObject.method(any()))
          .thenReturn(expectedReturn);
      
      // when 
      val result = underTest.method();
      
      // then
      assertEquals(enumParam, result.getCode());

   }

}

尝试的解决方法(MethodSource版本)

改用@MethodSource提供测试数据,返回Mock方法的入参和预期返回对象,但问题仍未解决:

@RunWith(MockitoJUnitRunner.class)
public class FooTest {

   @Mocked
   MockedObject mockedObject;

   @InjectMocks
   Foo underTest;

   @ParameterizedTest
   @MethodSource("dataProvider")
   public void test_ParametrizedTest(MockedInput mockedInput, Output expectedReturn) {

      // Given
      when(mockedObject.method(mockedInput))
         .thenReturn(expectedReturn);

     // when 
     val result = underTest.method();

     // then
     assertEquals(expectedReturn.getCode(), result.getCode());

  }
  
  private static Stream<Arguments> dataProvider() {
     return Stream.of(
              Arguments.of(mockedInput1, Output.builder().code(CodeEnum.S1).build()),
              Arguments.of(mockedInput2, Output.builder().code(CodeEnum.S2).build())
     );
  }

}

提问

如何实现让Mock对象返回参数化测试中的参数?


解决方案

问题根源分析

  1. JUnit版本冲突:@RunWith(MockitoJUnitRunner.class)是JUnit 4的运行器,和JUnit 5的@ParameterizedTest不兼容,这才是抛出匹配器异常的核心原因,和any()本身无关。
  2. MethodSource版本的额外问题:dataProvider里的mockedInput1、mockedInput2是未初始化的变量,直接使用会导致对象为空,同时仍存在JUnit版本冲突的问题。
  3. 注解错误:普通Mockito用@Mock注解,而非@Mocked(后者是PowerMock的注解)。

正确实现方式

方式一:保留枚举源,修复版本兼容问题

替换JUnit 4的运行器为JUnit 5的Mockito扩展,确保依赖使用JUnit Jupiter和Mockito的JUnit 5适配包:

@ExtendWith(MockitoExtension.class)
public class FooTest {
   
   @Mock
   MockedObject mockedObject;
   
   @InjectMocks
   Foo underTest;

   @ParameterizedTest
   @EnumSource(CodeEnum.class)
   public void test_ParametrizedTest(CodeEnum enumParam) {
      
      Output expectedReturn = Output.builder().code(enumParam).build();
      
      // Given
      when(mockedObject.method(any()))
          .thenReturn(expectedReturn);
      
      // when 
      FooResult result = underTest.method(); // 若用lombok的val需确保依赖正确
      
      // then
      assertEquals(enumParam, result.getCode());

   }

}

方式二:使用MethodSource,正确构造测试数据

同样替换为JUnit 5的扩展,并在dataProvider中初始化测试用的MockedInput对象:

@ExtendWith(MockitoExtension.class)
public class FooTest {

   @Mock
   MockedObject mockedObject;

   @InjectMocks
   Foo underTest;

   @ParameterizedTest
   @MethodSource("dataProvider")
   public void test_ParametrizedTest(MockedInput mockedInput, Output expectedReturn) {

      // Given
      when(mockedObject.method(mockedInput))
         .thenReturn(expectedReturn);

     // when 
     FooResult result = underTest.method();

     // then
     assertEquals(expectedReturn.getCode(), result.getCode());

  }
  
  private static Stream<Arguments> dataProvider() {
     // 正确初始化MockedInput实例,比如用构造器或builder
     MockedInput input1 = new MockedInput("testInput1");
     MockedInput input2 = new MockedInput("testInput2");
     
     return Stream.of(
              Arguments.of(input1, Output.builder().code(CodeEnum.S1).build()),
              Arguments.of(input2, Output.builder().code(CodeEnum.S2).build())
     );
  }

}

关键注意事项

  • 必须统一使用JUnit 5的扩展机制,不能混用JUnit 4的@RunWith和JUnit 5的参数化注解,否则会导致Mockito逻辑和参数化测试逻辑冲突。
  • 确保Mockito注解正确,普通场景用@Mock而非@Mocked。
  • MethodSource提供的测试数据必须是已正确初始化的对象,不能直接引用未赋值的变量。

内容的提问来源于stack exchange,提问作者PodGen4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 17:51:45