首先,您应该知道我正在使用TestNG v6.8.8和Java JDK 6.我遇到了在不同版本的Linux和Mac OS 10.9.4上运行的问题。转到代码清单。
import org.testng.annotations.Factory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author rcourtright
* Date: 8/5/14
* Time: 4:50 PM
*/
public class ErsatzFactory {
private final List<String> testData;
public ErsatzFactory() {
testData = new ArrayList<String>();
int order = 0;
for (int i = 0 ; i < 9; i++) {
testData.add(order++ + "-Test");
}
Collections.sort(testData);
}
@Factory
public Object[] setUp() {
List<ErsatzTest> objects = new ArrayList<ErsatzTest>();
int order = 0;
for (String testDatum : testData) {
objects.add(
order,
new ErsatzTest(testDatum)
);
order++;
}
return objects.toArray();
}
}
import org.testng.ITest;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* @author rcourtright
* Date: 8/5/14
* Time: 4:45 PM
*/
//@Listeners(ErsatzListener.class)
public class ErsatzTest implements ITest {
private String order;
public ErsatzTest(String order) {
this.order = order;
}
@Test
public void justDoIt() {
System.out.println(order);
}
@Override
public String getTestName() {
return order;
}
}
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="ersatz-testing" verbose="1" >
<test name="ersatz-test-factory" preserve-order="true">
<classes>
<class name="ErsatzFactory"/>
</classes>
</test>
</suite>
所以你可以在我的构造中看到我有一个自然顺序的列表,我对该集合进行排序。工厂的工作是按顺序执行单个测试方法。通过调试,我发现Factory返回的集合按所需顺序排列。但这不是他们的执行方式。
使用TestNG支持的ant目标,这是执行顺序:
检测结果ersatz-test-executor: [testng] 5-Test [testng] 2-Test [testng] 7-Test [testng] 6-Test [testng] 4-Test [testng] 8-Test [testng] 1-Test [testng] 0-Test [testng] 3-Test [testng] [testng] =============================================== [testng] ersatz-testing [testng] Total tests run: 9, Failures: 0, Skips: 0 [testng] =============================================== [testng]
这是意料之外的,也是不可取的。很明显,这个测试是微不足道的,但它是一个相当复杂的系统测试的代理,我必须得到正确的执行顺序。
虽然这里没有列出,但我必须使用TestNG Listener进行后期测试结果处理,看来我必须使用Factory而不是独立的DataProvider。 (我已经在测试类声明中注释掉了Listener注释。)我应该注意Listener的工作没有发生。
因为只有一种方法,所以我不能使用优先级注释或方法依赖性。测试完全由数据驱动。数据是可排序的,如果内存服务,当我在测试类中使用DataProvider时,我得到了该顺序。但我也需要Listener来装饰测试结果报告,这促使我使用工厂。我应该注意,无论我是否使用监听器,都存在执行问题。如果您编译并运行此代码,我希望您会看到列出的结果似乎是随机顺序。
提前感谢您考虑此问题。
答案 0 :(得分:5)
好的,我怀疑了。我不理解方法拦截器的预处理能力。所以我创建了一个,我得到了我的有序测试。为了寻求解决方案的任何人的利益,我将在此处列出我的代码更改。
import org.testng.IMethodInstance;
import org.testng.IMethodInterceptor;
import org.testng.ITestContext;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* @author rcourtright
* Date: 8/11/14
* Time: 2:37 PM
*/
public class ErsatzMethodInterceptor implements IMethodInterceptor {
@Override
public List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context) {
Map<String,IMethodInstance> orders = new TreeMap<String,IMethodInstance>();
for (IMethodInstance iMethodInstance : methods) {
if (!iMethodInstance.getMethod().getMethodName().equals("justDoIt")) {
continue;
}
Object obj = iMethodInstance.getInstance();
if (!(obj instanceof ErsatzTest)) {
continue;
}
ErsatzTest ersatzTest = (ErsatzTest)obj;
String order = ersatzTest.getOrder();
orders.put(order,iMethodInstance);
}
List<IMethodInstance> tests = new ArrayList<IMethodInstance>(orders.size());
for (String order : orders.keySet()) {
IMethodInstance test = orders.get(order);
tests.add(test);
}
return tests;
}
}
import org.apache.log4j.Logger;
import org.testng.ITest;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* @author rcourtright
* Date: 8/5/14
* Time: 4:45 PM
*/
@Listeners(
{
ErsatzMethodInterceptor.class,
ErsatzListener.class
}
)
public class ErsatzTest implements ITest {
private Logger logger = Logger.getLogger(ErsatzTest.class);
private String order;
public ErsatzTest(String order) {
this.order = order;
}
public String getOrder() {
return order;
}
@Test
public void justDoIt() {
logger.info(order);
}
@Override
public String getTestName() {
return order;
}
}
import org.apache.log4j.Logger;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;
import org.testng.internal.BaseTestMethod;
import org.testng.internal.TestResult;
import java.lang.reflect.Field;
/**
* @author rcourtright
* Date: 7/29/14
* Time: 12:03 PM
*/
public class ErsatzListener extends TestListenerAdapter {
private Logger logger = Logger.getLogger(ErsatzListener.class);
private void setTestNameInXml(ITestResult tr) {
try {
Field mMethod = TestResult.class.getDeclaredField("m_method");
mMethod.setAccessible(true);
mMethod.set(tr, tr.getMethod().clone());
Field mMethodName = BaseTestMethod.class.getDeclaredField("m_methodName");
mMethodName.setAccessible(true);
mMethodName.set(tr.getMethod(), tr.getTestName());
} catch (IllegalAccessException ex) {
logger.error(ex.getLocalizedMessage(), ex);
} catch (NoSuchFieldException ex) {
logger.error(ex.getLocalizedMessage(), ex);
}
}
@Override
public void onTestSuccess(ITestResult tr) {
setTestNameInXml(tr);
super.onTestSuccess(tr);
}
@Override
public void onTestFailure(ITestResult tr) {
setTestNameInXml(tr);
super.onTestFailure(tr);
}
@Override
public void onTestSkipped(ITestResult tr) {
setTestNameInXml(tr);
super.onTestSkipped(tr);
}
}
测试执行结果
我假设你现在有了log4j,所以在类路径上只有一个可用的log4j.xml,这里我们订购了测试结果:
$ java org.testng.TestNG testng.xml
[TestNG] Running:
/Users/rcourtright/Desktop/ersatz/testng.xml
0 [main] INFO ErsatzTest - 0-Test
2 [main] INFO ErsatzTest - 1-Test
3 [main] INFO ErsatzTest - 2-Test
4 [main] INFO ErsatzTest - 3-Test
5 [main] INFO ErsatzTest - 4-Test
6 [main] INFO ErsatzTest - 5-Test
7 [main] INFO ErsatzTest - 6-Test
8 [main] INFO ErsatzTest - 7-Test
9 [main] INFO ErsatzTest - 8-Test
===============================================
ersatz-testing
Total tests run: 9, Failures: 0, Skips: 0
===============================================
最后,我没有意识到方法拦截器的强大功能,并且它在工厂做任何事情之后运行。也就是说,工厂方法不控制顺序,但可以通过使用拦截器来改变它。