本文介绍了在使用 JUnit 参数化测试和 Mockito 框架时,如何正确地配置和使用 Mock 对象,使其能够根据参数化测试的输入参数返回不同的值。重点在于 runner 的选择,通过使用 MockitoExtension 解决了 InvalidUseOfMatchersException 异常,并提供了一个可运行的示例代码。
在使用 JUnit 进行单元测试时,参数化测试可以方便地使用不同的输入数据运行相同的测试逻辑。结合 Mockito 框架,我们可以模拟外部依赖的行为,从而更好地隔离被测代码。然而,在参数化测试中,如果 Mock 对象的行为依赖于参数化测试的输入,可能会遇到一些问题。本文将介绍如何正确地配置和使用 Mock 对象,使其能够根据参数化测试的输入参数返回不同的值。
问题分析
在使用 Mockito 时,常见的错误之一是 InvalidUseOfMatchersException,这通常发生在参数匹配器(如 any())被错误地使用时。例如,在没有进行 stubbing 或 verification 的情况下使用了参数匹配器。
解决方案
解决此问题的关键在于正确地配置 JUnit 运行器和 Mockito 扩展。以下是推荐的步骤:
使用 MockitoExtension:
确保你的测试类使用了 MockitoExtension 作为 JUnit 的扩展。这可以通过在类上添加 @ExtendWith(MockitoExtension.class) 注解来实现。MockitoExtension 负责初始化 Mockito 的 Mock 对象,并处理相关的生命周期。
@ExtendWith(MockitoExtension.class) public class FooTest { @Mock MockedObject mockedObject; @InjectMocks Foo underTest; // ... }
注意:这里使用了 @Mock 注解,它与 @Mocked 注解功能类似,都是用来创建 Mock 对象的。但 @Mock 是 Mockito 提供的标准注解,建议使用它。
参数化测试数据提供:
使用 @MethodSource 注解指定一个提供参数化测试数据的静态方法。该方法返回一个 Stream
@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() { MockedInput mockedInput1 = new MockedInput("S1"); MockedInput mockedInput2 = new MockedInput("S2"); return Stream.of( Arguments.of(mockedInput1, Output.builder().code(CodeEnum.S1).build()), Arguments.of(mockedInput2, Output.builder().code(CodeEnum.S2).build()) ); }
在这个例子中,dataProvider 方法返回一个包含 MockedInput 和 Output 对象的 Stream。每个 Arguments 对象都对应一个测试用例。
Mock 对象的 Stubbing:
在测试方法中,使用 when(mockedObject.method(mockedInput)).thenReturn(expectedReturn) 来指定 Mock 对象的行为。这里,mockedInput 是参数化测试的输入参数,expectedReturn 是期望的返回值。Mockito 会根据传入的 mockedInput 参数,返回相应的 expectedReturn 值。
断言:
最后,使用 assertEquals 或其他断言方法来验证被测代码的行为是否符合预期。
完整示例
以下是一个完整的示例代码,展示了如何在 JUnit 参数化测试中使用 Mockito 模拟对象,并根据不同的输入参数返回不同的值:
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import static org.mockito.Mockito.when; import static org.junit.jupiter.api.Assertions.assertEquals; import lombok.Builder; import lombok.Data; import lombok.Value; import java.util.stream.Stream; @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 Output result = underTest.method(mockedInput); // then assertEquals(expectedReturn.getCode(), result.getCode()); } private static Stream<Arguments> dataProvider() { MockedInput mockedInput1 = new MockedInput("S1"); MockedInput mockedInput2 = new MockedInput("S2"); return Stream.of( Arguments.of(mockedInput1, Output.builder().code(CodeEnum.S1).build()), Arguments.of(mockedInput2, Output.builder().code(CodeEnum.S2).build()) ); } // 辅助类 public static enum CodeEnum { S1("S1"), S2("S2"); private String value; CodeEnum(String value) { this.value = value; } public String getValue() { return value; } } @Value public static class MockedInput { String input; } @Builder @Data public static class Output { CodeEnum code; } public static class Foo { private MockedObject mockedObject; public Foo(MockedObject mockedObject) { this.mockedObject = mockedObject; } public Output method(MockedInput input) { return mockedObject.method(input); } } public static class MockedObject { public Output method(MockedInput input) { // This method will be mocked return null; } } }
注意事项
总结
通过使用 MockitoExtension 和 @MethodSource 注解,我们可以轻松地在 JUnit 参数化测试中使用 Mockito 模拟对象,并根据不同的输入参数返回不同的值。这种方法可以有效地隔离被测代码,并提高单元测试的质量。
以上就是JUnit 参数化测试中 Mock 对象返回参数化值的正确方法的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号