JUnit 参数化测试中 Mock 对象返回参数化值的正确方法

junit 参数化测试中 mock 对象返回参数化值的正确方法

本文介绍了在使用 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

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月1日 14:13:51
下一篇 2025年12月1日 14:36:36

相关推荐

发表回复

登录后才能评论
关注微信