我没有找到任何适合我的用例的方法。假设一个测试用例需要使用 2 个角色来执行,并且对于每个角色应该有 2 个使用不同数据的测试运行。
@Test (dataProviderClass = roles.class, dataProvider = roles.SUPERADMIN_ADMIN)
@Parameters({"data1", "data2"})
public void myTestCase () {
...
}
超级管理员和数据1、超级管理员和数据2、管理员和数据1、管理员和数据2
但这不起作用,因为参数应该在 xml 文件中设置,并且不支持多个 dataProvider。
任何有关如何解决此问题的高级帮助将不胜感激。
TestNG 不允许您将单个测试方法绑定到多个数据提供者。
话虽这么说,这里有一个示例,展示了如何使数据提供程序足够动态,以便它根据从套件文件传递的参数来修改自身。
public record Movie(String name) {}
public record Book(String name) {}
import org.testng.ITestNGMethod;
import org.testng.annotations.CustomAttribute;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlInclude;
import org.testng.xml.XmlTest;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class SampleTestCase {
private static final Object[][] defaultData = new Object[][]{
{true},
{false}
};
private static final List<Object> books = List.of(
new Book("Next Generation Java Testing"),
new Book("Head First Java")
);
private static final List<Object> movies = List.of(
new Movie("KungFu Panda"),
new Movie("The Last Air Bender")
);
private static final Map<String, List<Object>> dataStore = Map.of(
"data_set1", books,
"data_set2", movies
);
@Test(attributes = {
@CustomAttribute(name = "id1") // Hinting that this method is to get a parameter named "id1" from xml
}, dataProvider = "dp")
public void testMethod1(Book id) {
System.err.println("testMethod1() Book = " + id);
}
@Test(attributes = {
@CustomAttribute(name = "id2") // Hinting that this method is to get a parameter named "id2" from xml
}, dataProvider = "dp")
public void testMethod2(Movie id) {
System.err.println("testMethod2() Movie = " + id);
}
@Test(dataProvider = "dp")
public void testMethod3(boolean flag) {
System.err.println("Flag = " + flag);
}
@DataProvider(name = "dp")
public Object[][] getData(ITestNGMethod method) {
CustomAttribute[] attributes = method.getAttributes();
if (attributes.length == 0) {
//No annotation was found. So send back default data provider values
return defaultData;
}
//Now let's try to read the parameters that were set
Map<String, String> localParams = extractParameters(method);
for (CustomAttribute attribute : attributes) {
boolean present = localParams.containsKey(attribute.name());
if (!present) {
continue;
}
String whichDataSet = localParams.get(attribute.name());
List<Object> datum = Optional.ofNullable(dataStore.get(whichDataSet))
.orElseThrow(() -> new IllegalArgumentException("No data found for " + whichDataSet));
return datum.stream()
.map(it -> new Object[]{it})
.toArray(size -> new Object[size][1]);
}
//if we are here, then send back another default data
return defaultData;
}
private static Map<String, String> extractParameters(ITestNGMethod method) {
Class<?> requiredClass = method.getRealClass();
String requiredMethod = method.getMethodName();
XmlTest currentTest = method.getXmlTest();
XmlClass filter = new XmlClass(requiredClass);
XmlInclude result = null;
for (XmlClass each : currentTest.getXmlClasses()) {
if (!each.equals(filter)) {
//If the class name does not match, then skip to the next class in the suite file
continue;
}
Optional<XmlInclude> found = each.getIncludedMethods().stream()
.filter(it -> it.getName().equalsIgnoreCase(requiredMethod))
.findFirst();
if (found.isPresent()) {
//if we found a method that matches the method we are searching for, then remember it
// and break the loop
result = found.get();
break;
}
}
//Now try to extract out the local parameters associated with the <include> tag
//If there were none found, then error out with an exception
return Optional.ofNullable(result)
.map(XmlInclude::getLocalParameters)
.orElseThrow(() -> new IllegalArgumentException(requiredClass.getName() + "." + requiredMethod + "() combo not found"));
}
}
这是我们将要使用的套件文件
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="2980_suite" verbose="2">
<test name="2980_test" verbose="2">
<classes>
<class name="com.rationaleemotions.so.qn78064092.SampleTestCase">
<methods>
<include name="testMethod1">
<parameter name="id1" value="data_set1"/>
</include>
</methods>
</class>
<class name="com.rationaleemotions.so.qn78064092.SampleTestCase">
<methods>
<include name="testMethod2">
<parameter name="id2" value="data_set2"/>
</include>
</methods>
</class>
<class name="com.rationaleemotions.so.qn78064092.SampleTestCase">
<methods>
<include name="testMethod3"/>
</methods>
</class>
</classes>
</test>
</suite>
这是执行输出:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
...
... TestNG 7.9.0 by Cédric Beust ([email protected])
...
testMethod1() Book = Book[name=Next Generation Java Testing]
testMethod1() Book = Book[name=Head First Java]
testMethod2() Movie = Movie[name=KungFu Panda]
testMethod2() Movie = Movie[name=The Last Air Bender]
Flag = false
Flag = true
PASSED: com.rationaleemotions.so.qn78064092.SampleTestCase.testMethod2(Movie[name=KungFu Panda])
Test Attributes: <id2, []>
PASSED: com.rationaleemotions.so.qn78064092.SampleTestCase.testMethod2(Movie[name=The Last Air Bender])
Test Attributes: <id2, []>
PASSED: com.rationaleemotions.so.qn78064092.SampleTestCase.testMethod3(false)
PASSED: com.rationaleemotions.so.qn78064092.SampleTestCase.testMethod1(Book[name=Next Generation Java Testing])
Test Attributes: <id1, []>
PASSED: com.rationaleemotions.so.qn78064092.SampleTestCase.testMethod1(Book[name=Head First Java])
Test Attributes: <id1, []>
PASSED: com.rationaleemotions.so.qn78064092.SampleTestCase.testMethod3(true)
===============================================
2980_test
Tests run: 3, Failures: 0, Skips: 0
===============================================
===============================================
2980_suite
Total tests run: 6, Passes: 6, Failures: 0, Skips: 0
===============================================
Process finished with exit code 0