重新运行整个类而不仅仅是@Test在TestNG中

9

我在浏览stackoverflow几天了,试图找到如何重新运行整个测试类,而不仅仅是一个@Test步骤的方法。许多人说这在TestNG和IRetryAnalyzer中不受支持,而有些人发布了一些解决方法,但并不真正起作用。

有人成功实现过吗?

仅为澄清原因,以避免出现回答说这是有意不支持的情况:TestNG不仅是开发人员的工具。这意味着它也被软件测试人员用于端对端测试。端对端测试可能有依赖于前一个步骤的步骤。因此,重新运行整个测试类是有效的,而不仅仅是简单的@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
请编辑您的问题,包括一个示例,并展示您的期望。这将有助于他人给出符合您期望的答案。 - Krishnan Mahadevan
@AndiCover 链接指向那些不起作用的解决方法(或者是破坏TestNG逻辑的解决方法):https://dev59.com/V4Pba4cB1Zd3GeqPqErThttps://stackoverflow.com/questions/50241880/retry-logic-retry-whole-class-if-one-tests-fails-seleniumhttps://stackoverflow.com/questions/53736621/rerun-whole-class-in-case-of-failed-test-case-using-testng - gandalf_the_cool
1个回答

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种方法中有3种带有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执行是否成功。可能有一百万种更好的方法来做到这一点,但目前为止这样做就可以了。我为重试执行设置了一个监听器。您可以在上面的中看到它,它由以下内容组成:
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个测试的一部分。

Final report


我知道这不是你要找的,但在TestNG添加该功能之前,我希望它能对你有所帮助。


哎呀..我忘记在主监听器中添加一个条件,只有当重试套件发生且成功时才更新最终报告。现在已添加。 - Rodrigo Vaamonde

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接