
本文介绍了在使用 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,其中每个 Arguments 对象包含测试方法的输入参数。
@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 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 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; } }}
注意事项
确保你的 JUnit 和 Mockito 版本兼容。避免在参数化测试中使用过于复杂的参数匹配器,尽量使用具体的参数值进行 Mock 对象的 stubbing。如果遇到 InvalidUseOfMatchersException,首先检查是否正确地使用了 MockitoExtension,并确保参数匹配器只在 stubbing 或 verification 中使用。
总结
通过使用 MockitoExtension 和 @MethodSource 注解,我们可以轻松地在 JUnit 参数化测试中使用 Mockito 模拟对象,并根据不同的输入参数返回不同的值。这种方法可以有效地隔离被测代码,并提高单元测试的质量。
以上就是JUnit 参数化测试中 Mock 对象返回参数化值的正确方法的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/142575.html
微信扫一扫
支付宝扫一扫