Как заказать выполнение 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
===============================================

В конце концов, я не оценил силу метода-перехватчика и то, что он работает после того, как фабрика делает все, что делает. То есть фабричный метод не контролирует порядок, но это можно изменить с помощью перехватчика.

Другие вопросы по тегам