java - 如何测试依赖于初始参数的方法?

标签 java junit parameters junit5

在我的测试类中,我有几个参数化方法,其中参数是对象初始化的一部分。我对所有这些参数使用相同的参数,然后测试依赖于一个或多个参数的方法。

@MethodSource(value = "validSizes")
@ParameterizedTest
void testGetHeight(int terrainWidth, int height) {
    World world = new World(terrainWidth, height);
    assertEquals(height, world.getHeight());
}

这可能会导致代码重复——我需要重复参数、World 构造和@MethodSource 注释。

我想避免代码重复,因为如果我向构造函数添加另一个参数,我将不得不更改所有依赖于参数的测试方法。

我可以使用 @BeforeEach 注释来实现吗,即参数化 setUp() 方法,或者以其他方式实现?使用不同参数测试此类方法是否是一种好的做法?

最佳答案

您可以编写自己的 Argument Provider,它提供一个完全构造的世界对象并将其注入(inject)到您的 setup/BeforeEach 方法中(您将其存储在其中以供在测试方法中使用)。通过这种方式,您可以最大限度地减少设置代码并将初始化逻辑压缩到代码中的一个特定位置。

编辑:我想到了一个错误的机制。所以这里是正确的例子,它澄清了我的意思:

让我们假设您的世界对象看起来像这样:

class World {
    private final int width;
    private final int height;

    public World(int width, int height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public String toString() {
        return "World{" + "width=" + width + ", height=" + height + '}';
    }
}

你有几个测试方法,你需要一组不同的世界对象(可能是动态创建的),像这样:

class ArgumentProviderTest {
    @ParameterizedTest
    @ArgumentsSource(WorldArgumentProvider.class)
    void yourFirstTest(World w) {
        System.out.println(w);
    }

    @ParameterizedTest
    @ArgumentsSource(WorldArgumentProvider.class)
    void yourSecondTest(World w) {
        System.out.println(w);
    }
}

在这里您可以看到,所有测试都需要一个 World 对象作为参数。现在我们需要一种方法来提供世界对象。为此,我们编写了自己的 ArgumentsProvider,它也很简单:

class WorldArgumentProvider implements ArgumentsProvider {

    private Collection<World> createWorlds() {
        // Somehow create a bunch of World objects
        // !!! Here goes your initialization logic. !!!
        return ThreadLocalRandom.current()
                .ints()
                .limit(10)
                .mapToObj(i -> new World(i % 100, i / 100))
                .collect(Collectors.toList());
    }

    @Override
    public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
        // create an Arguments object from these (discrete) worlds.
        // remember: one method takes one Arguments object which carries each single argument/parameter
        return createWorlds().stream().map(Arguments::of);
    }
}

在这里,您可以在完整的编译器支持下做任何您想做的事情(而不是将方法名称用作字符串)。

也许您可以使用 DynamicTests 和 @TestFactory 实现类似的行为,但这取决于您的具体测试。


我的第一个想法是使用 ParameterResolver,它基本上是这样工作的:

  1. 将 ParameterResolver 注册为扩展(在此上下文中是在类级别而不是方法级别)
  2. 为您的测试和生命周期方法(BeforeEach/AfterAll/...)的每个(未解析的)参数调用此解析器
  3. 它决定它是否真的可以解析这个参数(例如正确的类型、正确的索引等等)
  4. 它提供实际的 Argument 作为参数

但是,使用这种机制,您无法告诉 Jupiter 引擎为一个方法构造多个 Test 实例(Jupiter 为这种东西引入了 TestTemplate 的概念)。有趣的是,这个参数化类 conect 是在 jUnit-4 中实现的(作为参数化测试的唯一方法)并且据我所知,这是一个有望在未来在 Jupiter 中出现的功能。我很期待。

关于java - 如何测试依赖于初始参数的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57171656/

相关文章:

java - ScrollTo 返回并出错,即使在该位置该元素是可单击的

java - 为什么很多 Maven 依赖版本都以 SNAPSHOT 结尾?

java - 使用 cucumber-java 和 junit 时如何获取 cucumber RuntimeOptions 的引用?

java - 使用抽象类进行通用测试

powershell - 在 PowerShell 中使用数字作为开关参数

java - 如何使用 Android 应用程序从 servlet 重复获取数据

java - 在Java中,如果父类有psvm,为什么我们不能使用名称为String的内部类

junit - IntelliJ 运行单元测试时出错 : Could not find or load main class ${surefireArgLine}

JavaScript 函数,将 HTML 作为参数传递

parameters - Struts2从Request GET类型获取参数