Как заказать выполнение TestNG Factory при наличии одного метода испытаний и сортируемых данных испытаний?
Прежде всего, вы должны знать, что я использую 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;
}
}
TestNG XML
<!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>
Итак, вы можете видеть в моей конструкции, у меня есть список, который имеет естественный порядок, и я сортирую эту коллекцию. Фабрика должна выполнять один метод тестирования в этом порядке. Отладкой я обнаружил, что коллекция, возвращаемая Фабрикой, находится в нужном порядке. Но это не так, как они выполняются.
Используя муравей, поддерживаемый TestNG, это порядок выполнения:
Результаты теста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 для обработки результатов после тестирования, и кажется, что я должен использовать Factory, а не автономный DataProvider. (Я прокомментировал аннотацию Listener в объявлении класса теста.) Следует отметить, что Listener работает без инцидентов.
Поскольку существует один и только один метод, я не могу использовать аннотацию Priority или зависимости метода. Тест полностью основан на данных. Данные сортируются и, если память не изменяет, когда я использовал DataProvider из тестового класса, я получил этот порядок. Но мне также нужен Слушатель для оформления отчетов о результатах испытаний, и это заставило меня использовать фабрику. Я должен отметить, что проблема выполнения существует независимо от того, использую я слушателя или нет. Если вы скомпилируете и запустите этот код, я ожидаю, что вы увидите результаты в произвольном порядке.
Заранее спасибо за рассмотрение этой проблемы.
1 ответ
Хорошо, я подозревал это. Я не оценил возможности предварительной обработки метода-перехватчика. Итак, я создал один и получил заказанные тесты. Для тех, кто ищет решение, я перечислю изменения своего кода здесь.
Метод перехватчик
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
===============================================
В конце концов, я не оценил силу метода-перехватчика и то, что он работает после того, как фабрика делает все, что делает. То есть фабричный метод не контролирует порядок, но это можно изменить с помощью перехватчика.