有没有办法使用 TestNG 数据提供程序为测试用例指定特定名称?
Is there a way to give a specific name to test case using TestNG data providers?
我正在 Java 中使用 @DataProvider
和 TestNG 6.14.3 编写单元测试
我想达到的目标:
- 我想为每个数据提供者案例命名。
- 我不想将名称作为参数之一,而是自定义名称。 (只是一个例子:“良好的流程没有授权”)
我尝试过的:
我添加了一个额外的参数并遵循了这个guide,
问题是现在我在每个我不想要的测试中都有一个未使用的参数caseName
。
创建一个忽略第一个参数的自定义 DataProvider
注释,这没有用,因为我找不到将它与 TestNG
集成的方法。
我的问题:
- 是否有内置方法可以为测试用例指定特定名称?
- 如果对 1 的回答是“否”:有没有办法集成自定义 DataProvider 或在数据提供给测试本身之前拦截数据?
- 即使按照这个 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
并且测试将从您的数据中获取他们的名字:
我正在 Java 中使用 @DataProvider
和 TestNG 6.14.3 编写单元测试我想达到的目标:
- 我想为每个数据提供者案例命名。
- 我不想将名称作为参数之一,而是自定义名称。 (只是一个例子:“良好的流程没有授权”)
我尝试过的:
我添加了一个额外的参数并遵循了这个guide, 问题是现在我在每个我不想要的测试中都有一个未使用的参数
caseName
。创建一个忽略第一个参数的自定义
DataProvider
注释,这没有用,因为我找不到将它与TestNG
集成的方法。
我的问题:
- 是否有内置方法可以为测试用例指定特定名称?
- 如果对 1 的回答是“否”:有没有办法集成自定义 DataProvider 或在数据提供给测试本身之前拦截数据?
- 即使按照这个 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
并且测试将从您的数据中获取他们的名字: