首页 > Java > java教程 > 正文

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

花韻仙語
发布: 2025-07-08 18:04:12
原创
116人浏览过

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

本文介绍了在使用 JUnit 参数化测试和 Mockito 框架时,如何正确地配置和使用 Mock 对象,使其能够根据参数化测试的输入参数返回不同的值。重点在于 runner 的选择,通过使用 MockitoExtension 解决了 InvalidUseOfMatchersException 异常,并提供了一个可运行的示例代码。

在使用 JUnit 进行单元测试时,参数化测试可以方便地使用不同的输入数据运行相同的测试逻辑。结合 Mockito 框架,我们可以模拟外部依赖的行为,从而更好地隔离被测代码。然而,在参数化测试中,如果 Mock 对象的行为依赖于参数化测试的输入,可能会遇到一些问题。本文将介绍如何正确地配置和使用 Mock 对象,使其能够根据参数化测试的输入参数返回不同的值。

问题分析

在使用 Mockito 时,常见的错误之一是 InvalidUseOfMatchersException,这通常发生在参数匹配器(如 any())被错误地使用时。例如,在没有进行 stubbing 或 verification 的情况下使用了参数匹配器。

解决方案

解决此问题的关键在于正确地配置 JUnit 运行器和 Mockito 扩展。以下是推荐的步骤:

  1. 使用 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 提供的标准注解,建议使用它。

  2. 参数化测试数据提供

    使用 @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<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 对象都对应一个测试用例。

  3. Mock 对象的 Stubbing

    在测试方法中,使用 when(mockedObject.method(mockedInput)).thenReturn(expectedReturn) 来指定 Mock 对象的行为。这里,mockedInput 是参数化测试的输入参数,expectedReturn 是期望的返回值。Mockito 会根据传入的 mockedInput 参数,返回相应的 expectedReturn 值。

  4. 断言

    最后,使用 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;
        }
    }
}
登录后复制

注意事项

  • 确保你的 JUnit 和 Mockito 版本兼容。
  • 避免在参数化测试中使用过于复杂的参数匹配器,尽量使用具体的参数值进行 Mock 对象的 stubbing。
  • 如果遇到 InvalidUseOfMatchersException,首先检查是否正确地使用了 MockitoExtension,并确保参数匹配器只在 stubbing 或 verification 中使用。

总结

通过使用 MockitoExtension 和 @MethodSource 注解,我们可以轻松地在 JUnit 参数化测试中使用 Mockito 模拟对象,并根据不同的输入参数返回不同的值。这种方法可以有效地隔离被测代码,并提高单元测试的质量。

以上就是JUnit 参数化测试中 Mock 对象返回参数化值的正确方法的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
相关标签:
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号