我使用Testng xml为我的测试配置参数。
不同的用户可能在xml文件中有不同的参数,我希望避免重复xml代码。
这个想法是每个用户定义一个包含所需参数的套件:
<suite name="Patrick's test file">
<parameter name="favoriteApple" value="gala"/>
<parameter name="favoriteGrape" value="red"/>
<suite-file>
<suite-file path="test.xml"/>
</suite-file>
</suite>
请注意,其他用户可能拥有不同的测试文件,其中包含favoriteApple和favoriteGrape的不同值。 test.xml看起来像这样:
<suite name="test">
<test>
<parameter name="fruit" value="VALUE OF favoriteApple PARAMETER"/>
<packages>
<package name="apple fruit test"/>
</packages>
</test>
<test>
<parameter name="fruit" value="VALUE OF favoriteGrape PARAMETER"/>
<packages>
<package name="grape fruit test"/>
</packages>
</test>
</suite>
测试结构的动机是每个包都有一个扩展抽象类的类。抽象类有一个设置方法@BeforeTest,它将参数接收到受保护的成员中。
我还没有找到一种方法来将参数值设置为另一个参数的值。
现在每个人都需要一个带有重复代码的xml文件进行测试。
感谢您的帮助!
答案 0 :(得分:1)
除了另一个答案中提供的侦听器之外,还有另一种实现侦听器的方法。
import java.util.Map;
import org.testng.Assert;
import org.testng.ITestContext;
import org.testng.TestListenerAdapter;
import org.testng.xml.XmlTest;
public class CustomListen3 extends TestListenerAdapter {
/**
* Invoked after test class in initialized and before all the getters and
* setters are called.
*/
@Override
public void onStart(ITestContext context) {
// Get the current test
XmlTest currentTest = context.getCurrentXmlTest();
// Get all the parameters Global and local
Map<String, String> parameters = currentTest.getAllParameters();
for (String key : parameters.keySet()) {
String parameterValue = parameters.get(key);
// If parameter value starts with $, replace with the global parameter value
if (parameterValue.startsWith("$")) {
String newValue = currentTest.getParameter(parameterValue.substring(1));
Assert.assertNotNull(newValue, "Global parameter value, " + parameterValue.substring(1));
parameters.put(key, newValue);
}
}
// Update the new parameters
currentTest.setParameters(parameters);
super.onStart(context);
}
}
唯一的小问题是本地参数值被全局参数值覆盖。
答案 1 :(得分:0)
这可以通过以下步骤来实现
$
等字符在各个测试文件中提供对这些全局参数的引用。 $
开头,则testNG应查找全局参数。此实施应在custom listener
。$
symobol,则将按原样使用参数值。这样就可以灵活地运行test.xml而无需使用全局套件文件<强> global_suite.xml 强>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Sighil's test file">
<parameter name="favoriteApple" value="gala" />
<parameter name="favoriteGrape" value="red" />
<listeners>
<listener class-name="path to CustomListen"></listener>
</listeners>
<suite-files>
<suite-file path="testng_3.xml" />
</suite-files>
</suite>
<强>的test.xml 强>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="test" parallel="none">
<test verbose="2" name="AppleTest" enabled="true">
<parameter name="fruit" value="$favoriteApple" />
<classes>
<class name="com.project.ppp.AppleTest" />
</classes>
</test>
<test verbose="2" name="GrapeTest" enabled="true">
<parameter name="fruit" value="$favoriteGrape" />
<classes>
<class name="com.project.ppp.GrapeTest" />
</classes>
</test>
</suite>
<强> CustomListen.java 强>
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.testng.Assert;
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener2;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.annotations.Parameters;
import org.testng.xml.XmlTest;
public class CustomListen implements IInvokedMethodListener2 {
@Override public void beforeInvocation(IInvokedMethod invokedMethod, ITestResult testResult) {}
@Override public void afterInvocation(IInvokedMethod invokedMethod, ITestResult testResult) {}
@Override public void beforeInvocation(IInvokedMethod invokedMethod, ITestResult testResult, ITestContext context) {}
@Override
public void afterInvocation(IInvokedMethod invokedMethod, ITestResult testResult, ITestContext context) {
ITestNGMethod testNGMethod = invokedMethod.getTestMethod();
XmlTest currentTest = context.getCurrentXmlTest();
// if method invoked is setFruit
if (testNGMethod.isBeforeTestConfiguration() && testNGMethod.getMethodName().equals("setFruit")) {
// find the java.lang.reflect method
Method method = testNGMethod.getConstructorOrMethod().getMethod();
// Get the parameters defined setFruit
Parameters parameter = method.getAnnotation(Parameters.class);
if (parameter != null) {
// get the parameter names
String[] parameterNames = parameter.value();
// initiate a String array to hold the parameter values
String[] parameterValues = new String[parameterNames.length];
boolean setNewParameterValue = false;
// loop the parameter names to get their corresponding parameter values
for (int index = 0; index < parameterNames.length; index++) {
// set the parameter value
parameterValues[index] = currentTest.getParameter(parameterNames[index]);
// check if parameter value set expects a global parameter value
if (parameterValues[index].startsWith("$")) {
String newParameterValue = currentTest.getParameter(parameterValues[index].substring(1));
// Check if global parameter value is set
Assert.assertNotNull(newParameterValue,
"Global parameter name, " + parameterValues[index].substring(1));
parameterValues[index] = newParameterValue;
setNewParameterValue = true;
}
}
// invoke the setFruit BeforeTest method again to set the protected members if
// global parameters are required
if (setNewParameterValue) {
try {
method.invoke(testResult.getInstance(), (Object[]) parameterValues);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
}
我使用以下类
在 TestNG 6.14.3 上测试了上述内容public class GrapeTest extends FruitTest {
@Test
public void grapeTest() {
System.out.println("grapeTest - " + fruit);
}
}
public class AppleTest extends FruitTest {
@Test
public void appleTest() {
System.out.println("appleTest - " + fruit);
}
}
<强>输出强>
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running TestSuite
appleTest - gala
grapeTest - red
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.493 sec - in TestSuite