
本文介绍了在使用 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>,其中每个 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 对象都对应一个测试用例。
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号