Повторний запуск повного класу, а не тільки @Test в TestNG


9

Я вже кілька днів переглядаю stackoverflow, намагаючись знайти, як запустити цілий тестовий клас, а не лише @Testкрок. Багато хто каже, що це не підтримується в TestNG, і IRetryAnalyzer, хоча деякі публікують обхідні шляхи, вони насправді не працюють. Хтось встиг це зробити? І лише для з’ясування причин цього, щоб уникнути відповідей, які говорять, що це не підтримується за призначенням: TestNG - це інструмент не тільки для розробників. Значення, яке також використовується SW-тестерами для тестування e2e. Тести E2e можуть мати етапи, які залежать від попереднього. Так що так, це дійсно для повторного запуску цілого класу тестів, а не простого @Test, що легко зробити через IRetryAnalyzer.

Прикладом того, чого я хочу досягти:

public class DemoTest extends TestBase {

@Test(alwaysRun = true, description = "Do this")
public void testStep_1() {
    driver.navigate().to("http://www.stackoverflow.com");
    Assert.assertEquals(driver.getCurrentUrl().contains("stackoverflow)"));

}

@Test(alwaysRun = true, dependsOnMethods = "testStep_1", description = "Do that")
public void testStep_2() {
    driver.press("button");
    Assert.assertEquals(true, driver.elementIsVisible("button"));

}

@Test(alwaysRun = true, dependsOnMethods = "testStep_2", description = "Do something else")
public void testStep_3() {
   driver.press("button2");
Assert.assertEquals(true, driver.elementIsVisible("button"));

}

}

Скажімо, що testStep_2не вдається, я хочу повторитись class DemoTestі не простоtestStep_2


Чи можете ви показати нам рішення, яке не працює?
AndiCover

Будь ласка, відредагуйте своє запитання, включіть зразок та покажіть нам, які ваші очікування. Це допоможе допомогти іншим дати відповідь, що відповідає вашим очікуванням.
Крішнан Махадеван

@AndiCover Посилання на обхідні шляхи , які не працюють (або обхідні шляхи , які руйнують TestNG логіки): stackoverflow.com/questions/25781098 / ... stackoverflow.com/questions/50241880 / ... stackoverflow.com/questions/53736621 / ...
gandalf_the_cool

Відповіді:


1

Гаразд, я знаю, що ви, мабуть, хочете, щоб було легке властивість, яке ви можете вказати у своєму @BeforeClass або щось подібне, але нам, можливо, доведеться чекати, коли це буде здійснено. Принаймні, я теж не міг його знайти.

Далі це некрасиво, як пекло, але я думаю, що це робить роботу, принаймні в невеликих масштабах, залишається побачити, як він поводиться в більш складних сценаріях. Можливо, за допомогою більшого часу це можна вдосконалити в щось краще.

Гаразд, тому я створив тестовий клас, подібний до вашого:

public class RetryTest extends TestConfig {

    public class RetryTest extends TestConfig {

        Assertion assertion = new Assertion();

        @Test(  enabled = true,
                groups = { "retryTest" },
                retryAnalyzer = TestRetry.class,
                ignoreMissingDependencies = false)
        public void testStep_1() {
        }

        @Test(  enabled = true,
                groups = { "retryTest" },
                retryAnalyzer = TestRetry.class,
                dependsOnMethods = "testStep_1",
                ignoreMissingDependencies = false)
        public void testStep_2() {
            if (fail) assertion.fail("This will fail the first time and not the second.");
        }

        @Test(  enabled = true,
                groups = { "retryTest" },
                retryAnalyzer = TestRetry.class,
                dependsOnMethods = "testStep_2",
                ignoreMissingDependencies = false)
        public void testStep_3() {
        }

        @Test(  enabled = true)
        public void testStep_4() {
            assertion.fail("This should leave a failure in the end.");
        }

    }


У мене є Listenerсупер клас на той випадок, якщо я хотів би поширити це на інші класи, але ви також можете встановити слухача у вашому тестовому класі.

@Listeners(TestListener.class)
public class TestConfig {
   protected static boolean retrySuccessful = false;
   protected static boolean fail = true;
}


Три з 4 вище способів мають RetryAnalyzer. Я залишив це testStep_4без цього, щоб переконатися, що те, що я роблю далі, не псується з рештою страти. Саїд RetryAnalyzerнасправді не намагатиметься повторити (зауважте, що метод повертається false), але він зробить наступне:

public class TestRetry implements IRetryAnalyzer {

    public static TestNG retryTestNG = null;

    @Override
    public boolean retry(ITestResult result) {
        Class[] classes = {CreateBookingTest.class};

        TestNG retryTestNG = new TestNG();
        retryTestNG.setDefaultTestName("RETRY TEST");
        retryTestNG.setTestClasses(classes);
        retryTestNG.setGroups("retryTest");
        retryTestNG.addListener(new RetryAnnotationTransformer());
        retryTestNG.addListener(new TestListenerRetry());
        retryTestNG.run();

        return false;
    }

}


Це створить виконання всередині вашого виконання. Він не зіпсується із звітом, і як тільки він закінчиться, він продовжить основне виконання. Але це "повторить" методи всередині цієї групи.

Так, я знаю, я знаю. Це означає, що ви вічно будете виконувати свій тестовий набір у вічному циклі. Ось чому RetryAnnotationTransformer. У ньому ми видалимо RetryAnalyzer з другого виконання цих тестів:

public class RetryAnnotationTransformer extends TestConfig implements IAnnotationTransformer {

    @SuppressWarnings("rawtypes")
    @Override
    public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
        fail = false; // This is just for debugging. Will make testStep_2 pass in the second run.
        annotation.setRetryAnalyzer(null);
    }

}


Зараз у нас є останні з наших проблем. Наш оригінальний тестовий набір нічого не знає про те "повторне" виконання там. Тут стає по-справжньому потворно. Нам потрібно розповісти нашому Репортеру, що саме сталося. І це та частина, яку я заохочую вас до вдосконалення. Мені не вистачає часу, щоб зробити щось приємніше, але якщо я можу, я відредагую це в якийсь момент.

По-перше, ми повинні знати, чи успішно було виконано retryTestNG. Напевно, є мільйон способів зробити це краще, але наразі це працює. Я налаштував слухача саме для повторного виконання. Ви можете побачити його TestRetryвище, і він складається з наступного:

public class TestListenerRetry extends TestConfig implements ITestListener {

    (...)

    @Override
    public void onFinish(ITestContext context) {
        if (context.getFailedTests().size()==0 && context.getSkippedTests().size()==0) {
            successful = true;
        }
    }

}

Тепер слухач основного набору, той, якого ви бачили вище в суперкласі TestConfig, побачить, чи відбувся запуск і чи пішов він добре, і оновить звіт:

public class TestListener extends TestConfig implements ITestListener , ISuiteListener {

    (...)

    @Override
    public void onFinish(ISuite suite) {

        if (TestRetry.retryTestNG != null) {

            for (ITestNGMethod iTestNGMethod : suite.getMethodsByGroups().get("retryTest")) {

                Collection<ISuiteResult> iSuiteResultList = suite.getResults().values();

                for (ISuiteResult iSuiteResult : iSuiteResultList) {

                    ITestContext iTestContext = iSuiteResult.getTestContext();
                    List<ITestResult> unsuccessfulMethods = new ArrayList<ITestResult>();

                    for (ITestResult iTestResult : iTestContext.getFailedTests().getAllResults()) {
                        if (iTestResult.getMethod().equals(iTestNGMethod)) {
                            iTestContext.getFailedTests().removeResult(iTestResult);
                            unsuccessfulMethods.add(iTestResult);
                        }
                    }

                    for (ITestResult iTestResult : iTestContext.getSkippedTests().getAllResults()) {
                        if (iTestResult.getMethod().equals(iTestNGMethod)) {
                            iTestContext.getSkippedTests().removeResult(iTestResult);
                            unsuccessfulMethods.add(iTestResult);
                        }
                    }

                    for (ITestResult iTestResult : unsuccessfulMethods) {
                        iTestResult.setStatus(1);
                        iTestContext.getPassedTests().addResult(iTestResult, iTestResult.getMethod());
                    }

                }

            }

        }


    }

}

У звіті мають бути показані 3 пройдені тести (як вони були повторно), і один, який не вдався, оскільки він не був частиною інших 3 тестів:

Підсумковий звіт


Я знаю, що це не те, що ви шукаєте, але я допомагаю йому служити вам, поки вони не додадуть функціональності для TestNG.


На жаль, я забув додати умовного основного слухача, щоб оновити остаточний звіт лише в тому випадку, якщо стався пакет "Повторний набір" і він був успішним. Додано зараз.
Родріго Ваамонд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.