Повторний запуск повного класу, а не тільки @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.