有没有办法使用 TestNG 数据提供程序为测试用例指定特定名称?

Is there a way to give a specific name to test case using TestNG data providers?

我正在 Java 中使用 @DataProvider

和 TestNG 6.14.3 编写单元测试

我想达到的目标:

  1. 我想为每个数据提供者案例命名。
  2. 我不想将名称作为参数之一,而是自定义名称。 (只是一个例子:“良好的流程没有授权”)

我尝试过的:

  1. 我添加了一个额外的参数并遵循了这个guide, 问题是现在我在每个我不想要的测试中都有一个未使用的参数caseName

  2. 创建一个忽略第一个参数的自定义 DataProvider 注释,这没有用,因为我找不到将它与 TestNG 集成的方法。

我的问题:

  1. 是否有内置方法可以为测试用例指定特定名称?
  2. 如果对 1 的回答是“否”:有没有办法集成自定义 DataProvider 或在数据提供给测试本身之前拦截数据?
  3. 即使按照这个 guide 我仍然看到其他参数作为 Intellij 中的测试名称 postfix,这正常吗?如果没有,我将 post 我的示例代码。

谢谢!

一个解决方案可能是在测试 class 中声明一个 String 名称数组,然后按顺序进行。如果您不 运行 并行测试,这将起作用。

否则,您可以使用 @Factory 注释,它可以从数据提供者那里获取输入,然后创建测试对象。

@Factory(dataProvider = "data")
public Object[] createInstances(String val, String name) {
    return new Object[] { new MyTest(name) };
}

@DataProvider
public Object[][] data() {
    return new Object[][] { { "a", "one" }, { "b", "two" } };
}

因此您需要在测试 class 中有一个 name 字段,该字段将使用构造函数设置。结合 link 中建议的代码来设置测试名称,您可以这样做:

public class MyTest implements ITest {

    private String name;
    private ThreadLocal<String> testName = new ThreadLocal<>();

    public MyTest() {
    }

    public MyTest(String name) {
        this.name = name;
    }

    @Factory(dataProvider = "data")
    public Object[] createInstances(String name) {
        return new Object[] { new MyTest(name) };
    }
    
    @DataProvider
    public Object[][] data() {
        return new Object[][] { { "one" }, { "two" } };
    }

    @BeforeMethod
    public void beforeMethod(Method method) {
        testName.set(method.getName() + "_" + name);
    }

    @Test
    public void test() {
        System.out.println(name);
    }

    @Override
    public String getTestName() {
        return testName.get();
    }
}

编辑: 在不使用 Factory 的情况下,可以如下实现。这需要在ITestContext:

中设置相关的细节
@DataProvider
public Object[][] data(ITestContext ctx) {
    ctx.setAttribute("names", new String[]{"one", "two"});
    ctx.setAttribute("index", 0);
    
    return new Object[][] { {"val1", "data1"}, {"val2", "data2"} };
}

现在在 beforeMethod 中也注入 ITestContext:

@BeforeMethod
public void beforeMethod(ITestContext ctx, Method method) {
    testName.set(method.getName() + "_" + getName(ctx));
}

// Create a helper method getName.
private static String getName(ITestContext ctx) {
    int index = (int) ctx.getAttribute("index");
    // get the name based on the current index.
    String name = ((String[]) ctx.getAttribute("names"))[index++];
    
    // update the attribute with the incremented index.
    ctx.setAttribute("index", index);
    return name;
}

@Test(dataProvider = "data") 
public void yourTest(String val, String data) {
    // .............
}

注意: 当测试 运行 并行时,这将无法按预期工作。

你可以这样做:

public class TestName {

    @DataProvider(name = "nameAndOthers")
    Iterator<Object[]> provideData(ITestContext testContext){
        Object[][] data = new Object[][]{
                {"name1", 1, 2},
                {"name2", 3, 4},
                {"name3", 5, 6},
        };
        Iterator<Object[]> originalDataIterator = Arrays.asList(data).iterator();
        return new Iterator<Object[]>() {
            @Override
            public boolean hasNext() {
                return originalDataIterator.hasNext();
            }

            @Override
            public Object[] next() {
                Object[] next = originalDataIterator.next();
                testContext.getCurrentXmlTest().setName(next[0].toString());
                return Arrays.copyOfRange(next, 1, next.length);
            }
        };

    }

    @Test(dataProvider = "nameAndOthers")
    void testName(Integer one, Integer two){
        System.out.println(one + ": " + two);
    }

}

输出将是:

1: 2
3: 4
5: 6

并且测试将从您的数据中获取他们的名字: