在JUnit 5测试方法中输入多个参数

时间:2019-06-10 12:52:38

标签: java junit5

我想为我的代码库提供“多态”测试用例。具体来说,Graph接口将有多种实现,并且希望对其全部重用测试代码(ALGraphAMGraph,...)。

我想按照以下方式开发测试方法

    @ParameterizedTest
    @MethodSource("graphFactory")
    // Note: JUnit 5 won't allow the following additional argument source
    @ValueSource(ints = {0, 31415, -31415})
    void testInsertDeleteNode(Graph g, Integer v) {
        g.insertNode(new Node<>(v));
        assertTrue(g.containsNode(new Node<>(v)));
        assertEquals(1, g.vertices().size());

        g.deleteNode(new Node<>(v));
        assertFalse(g.containsNode(new Node<>(v)));
        assertEquals(0, g.vertices().size());
    }

但是JUnit的构建方式阻止了我完成此方案。

所以基本上,我想为测试提供多个参数的笛卡尔积。开箱即用的参数提供程序(ValueSourceNullSource,...)是否可行?或者我是否需要借助@MethodSource来设置自定义参数提供程序? ?

2 个答案:

答案 0 :(得分:3)

开箱即用不支持此功能,但是https://github.com/junit-team/junit5/issues/1427上已经存在功能请求

在此处找到示例和概念证明解决方案:https://github.com/junit-team/junit5-samples/tree/master/junit5-jupiter-extensions

@CartesianProductTest({"0", "1"})
void threeBits(String a, String b, String c) {
    int value = Integer.parseUnsignedInt(a + b + c, 2);
    assertTrue((0b000 <= value) && (value <= 0b111));
}

@CartesianProductTest
@DisplayName("S ⨯ T ⨯ U")
void nFold(String string, Class<?> type, TimeUnit unit, TestInfo info) {
    assertTrue(string.endsWith("a"));
    assertTrue(type.isInterface());
    assertTrue(unit.name().endsWith("S"));
    assertTrue(info.getTags().isEmpty());
}

static CartesianProductTest.Sets nFold() {
    return new CartesianProductTest.Sets()
            .add("Alpha", "Omega")
            .add(Runnable.class, Comparable.class, TestInfo.class)
            .add(TimeUnit.DAYS, TimeUnit.HOURS);
}

产生如下测试计划:

@CartesianProductTest example

答案 1 :(得分:1)

在您的示例中,您可能还考虑使用基于属性的测试框架,例如jqwik。第一种使用方式与您的示例非常相似:

import net.jqwik.api.*;
import static org.junit.jupiter.api.Assertions.*;

@Property(generation = GenerationMode.EXHAUSTIVE)
void testInsertDeleteNode(
        @ForAll("graphFactory") Graph g, 
        @ForAll("ints") Integer v) 
{
    g.insertNode(new Node<>(v));
    assertTrue(g.containsNode(new Node<>(v)));
    assertEquals(1, g.vertices().size());

    g.deleteNode(new Node<>(v));
    assertFalse(g.containsNode(new Node<>(v)));
    assertEquals(0, g.vertices().size());
}

@Provide
Arbitrary<Graph> graphFactory() {
    return Arbitraries.of(new ALGraph(), new AMGraph());
}

@Provide
Arbitrary<Integer> ints() {
    return Arbitraries.of(0, 31415, -31415);
}

使用generation = GenerationMode.EXHAUSTIVE告诉引擎生成 可能参数值的笛卡尔乘积。实际上,如果数量 组合是<= 1000 jqwik本身就可以用于笛卡尔产品。

根据不同Graph实现的数量,您还可以考虑 一种为每个实现使用具体子类的方法,以及 在接口(或抽象超类)中指定测试本身:

interface GraphTest<G extends Graph> {

    G createGraph();

    @Property(generation = GenerationMode.EXHAUSTIVE)
    default void testInsertDeleteNode(@ForAll("ints") Integer v) {
        Graph g = createGraph();
        g.insertNode(new Node<>(v));
        assertTrue(g.containsNode(new Node<>(v)));
        assertEquals(1, g.vertices().size());

        g.deleteNode(new Node<>(v));
        assertFalse(g.containsNode(new Node<>(v)));
        assertEquals(0, g.vertices().size());
    }

    @Provide
    default Arbitrary<Integer> ints() {
        return Arbitraries.of(0, 31415, -31415);
    }
}

class ALGraphTest implements GraphTest<ALGraph> {
    @Override
    public ALGraph createGraph() {
        return new ALGraph();
    }
}

class AMGraphTest implements GraphTest<AMGraph> {
    @Override
    public AMGraph createGraph() {
        return new AMGraph();
    }
}

由于您已经在使用JUnit 5平台,因此使用jqwik需要使用single additional dependency