简体   繁体   English

TestNG - 如何在每次测试结束时运行相同的方法

[英]TestNG - how to run the same method at the end of each test

I have something like:我有类似的东西:

@Test(priority = 1)
public void test1() {
    testSomething1();
    Assert.assertFalse(errorsExists());
}
    
@Test(priority = 2)
public void test2() {
    testSomething2();
    Assert.assertFalse(errorsExists());
}
    
@Test(priority = 3)
public void test3() {
    testSomething3();
    Assert.assertFalse(errorsExists());
}

and I would like to move Assert.assertFalse(errorsExists()) to BaseTestCase or to TestListener so I will not have to pass it every time at the end of the test.我想将Assert.assertFalse(errorsExists())移动到BaseTestCaseTestListener ,这样我就不必每次在测试结束时都通过它。 I tried to move it to TestsListener to onFinish but method errorsExists() requires driver and I have problems to get it in there.我试图将它移到 TestsListener 到onFinish但方法errorsExists()需要驱动程序,我有问题将它放在那里。

Update: I want to method errorsExists() influence test result.更新:我想方法 errorsExists() 影响测试结果。 Lets say that in test2 method errorsExists return true -> I want to have following results: test1 passed test2 failed test3 passed假设在 test2 方法中 errorsExists 返回 true -> 我想得到以下结果: test1 通过 test2 failed test3 通过

so as far as I know I cannot put this method to any @After annotations and I cannot put it to onTestFailure or onTestSuccess in TestListener据我所知,我不能将此方法放在任何 @After 注释中,也不能将其放在 TestListener 中的 onTestFailure 或 onTestSuccess

You should be able to move it to a new method annotated with @AfterMethod.您应该能够将其移至使用 @AfterMethod 注释的新方法。 Any method annotated with @AfterMethod will be executed after each test method is executed.任何带有@AfterMethod 注解的方法都将在每个测试方法执行后执行。 Something like this should work:像这样的东西应该工作:

@Test(priority = 1)
public void test1() {
  testSomething1();
  //Assert.assertFalse(errorsExists());
}

@Test(priority = 2)
public void test2() {
  testSomething2;
  //Assert.assertFalse(errorsExists());
}

@Test(priority = 3)
public void test3() {
  testSomething3();
  //Assert.assertFalse(errorsExists());
}

@AfterMethod
public void assertError() {
  Assert.assertFalse(errorsExists());
}

If you are running each of your @Test methods in parallel, then you can achieve this in the following way.如果您并行运行每个 @Test 方法,则可以通过以下方式实现此目的。 But the pre-requisite is, each @Test should have its own WebDriver instance.但前提是,每个 @Test 都应该有自己的 WebDriver 实例。 You can use ThreadLocal variable to achieve this.您可以使用 ThreadLocal 变量来实现这一点。 Eg:例如:

public class Driver {

    public static ThreadLocal<AppiumDriver> driver = new ThreadLocal<>();
  
    public static AppiumDriver getDriver() {
        return driver.get();
    }

public synchronized void initalizeDriver(String deviceName, String platformVersion, String port, String udid) {
        if (deviceName.contains("iPhone")) {
            setIOSCapabilities(driver, deviceName, platformVersion, port, udid);
        } else if (deviceName.equalsIgnoreCase("pcloudy-apple")) {
            setPcloudyIOSCapabilties(driver,platformVersion);
        } else {
            if (deviceName.contains("R-")) {
                setAndroidCapabilities(driver, deviceName, platformVersion, port, udid);
            } else if (deviceName.equalsIgnoreCase("pcloudy-Android")) {
                setPcloudyAndroidCapabilties(driver,platformVersion);
            } else {
                startAndroidEmulator(deviceName, udid);
                setAndroidCapabilities(driver, deviceName, platformVersion, port, udid);
            }
        }
    }
}

public void setAndroidCapabilities(ThreadLocal<AppiumDriver> driver, String device, String platformVersion, String port, String udid) {

        try {
            File sourceDir = new File("src");
            File app = new File(sourceDir, ANDROID_APP_PATH);

            DesiredCapabilities desiredCapabilties = new DesiredCapabilities();
            desiredCapabilties.setCapability(MobileCapabilityType.DEVICE_NAME, device);
            
            desiredCapabilties.setCapability(AndroidMobileCapabilityType.IGNORE_UNIMPORTANT_VIEWS,true);
            driver.set(new AndroidDriver<>(new URL(APPIUM_DEFAULT_URL), desiredCapabilties));
        } catch (Exception e) {
            log.error(e.getMessage());
            log.error("Exception in launching the Android Driver " + e);
            e.printStackTrace();
        }
    }

Method inside the base class to start a new driver instance for each @Test method基础 class 中的方法为每个 @Test 方法启动一个新的驱动程序实例

@BeforeMethod(alwaysRun = true)
@Parameters(value={"deviceName","platformVersion","port","udid"})
public synchronized void executeBeforeTest(String deviceName, String platformVersion,
                                               @Optional("Port Required") String port, @Optional("UDID Required") String udid){
        Driver driverObj = new Driver();
        Thread.currentThread().setName(deviceName);
        driverObj.initalizeDriver(deviceName,platformVersion,port,udid);
        if(Driver.getDriver() == null) {
            driverObj.initalizeDriver(deviceName,platformVersion,port,udid);
        }
    }

Finally the TestListener class you are looking for,最后是您正在寻找的 TestListener class,

public class TestListener extends UITest implements ITestListener {
@Override
    public void onTestFailure(ITestResult iTestResult) {
        log.info("Driver getDriver() value is :: "+Driver.getDriver().toString());
        log.info("Driver getSessionId() value is :: "+Driver.getDriver().getSessionId().toString());
            if (Driver.getDriver() != null || Driver.getDriver().getSessionId() != null) {
                try {
                    if (Driver.getDriver() instanceof IOSDriver) {
                        JavascriptExecutor js = (JavascriptExecutor) Driver.getDriver();
                        Map<String, Object> params = new HashMap<>();
                        params.put("bundleId", DeviceCapabalities.IOS_APP_BUNDLE_ID);
                        final Long state = (Long) js.executeScript("mobile: queryAppState", params);
                        System.out.println("Application state code is :" + state);
                        if (state == 1) {
                            log.error("Application has Crashed");
                        }
                    } else {
                        if (!(((AndroidDriver) (Driver.getDriver())).currentActivity().contains("app.name"))) {
                            log.error("Application has Crashed");
                        }
                    }
                    saveScreenshot(Driver.getDriver(),iTestResult);
                } catch (Exception e) {
                    log.error("Exception :: " + e);
                    e.printStackTrace();
                    Assert.fail("Test case failed due to exception " + e);
                }
            }
    }

You may use the IHookable interface to achieve this.您可以使用IHookable接口来实现这一点。 This is usually (according to the documentation), used to do some operations before the test start.这通常是(根据文档),用于在测试开始之前做一些操作。 But it works fine for operations at the end of each test as well.但它也适用于每次测试结束时的操作。

Create a BaseTest which implements this interface and let your test classes extend the BaseTest .创建一个实现此接口的BaseTest并让您的测试类扩展BaseTest

public class BaseTest implements IHookable {

    @Override
    public void run(IHookCallBack cb, ITestResult testResult) {
        cb.runTestMethod(testResult); // invokes the actual test case
        Assert.assertFalse(errorsExists());
    }
}

You can invoke some code and modify test results using IInvokedMethodListener .您可以使用IInvokedMethodListener调用一些代码并修改测试结果。

Note, that this is a very simple implementation just based on your code example.请注意,这是一个非常简单的实现,仅基于您的代码示例。 It may need some improvements.它可能需要一些改进。

Test Class:测试 Class:

@Listeners(ErrorsExistsListener.class)
class MyTest {

    @Test(priority = 1)
    public void test1() {
        testSomething1();
    }

    @Test(priority = 2)
    public void test2() {
        testSomething2;
    }

    @Test(priority = 3)
    public void test3() {
        testSomething3();
    }

    boolean errorsExists() {
        // some logic
    }
    

}

Test Listener:测试监听器:

class ErrorsExistsListener implements IInvokedMethodListener {

    @Override
    void afterInvocation(IInvokedMethod method, ITestResult result) {
        if (method.isTestMethod() && result.getStatus() != ITestResult.FAILURE) {
            Object[] instances = result.getTestClass().getInstances(false);
            MyTest myTestClass = (MyTest) instances[0]; // you'll get exception here if set this listener for non-MyTest class.
            try {
                Assert.assertFalse(myTestClass.errorsExists());
            } catch (AssertionError e) {
                result.setStatus(ITestResult.FAILURE);
                result.setThrowable(e);
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如果运行模式是 parallel=&quot;methods&quot;,如何强制 TestNG 为每个方法创建测试类的新实例 - How to force TestNG create new instance of test class for each method if run mode is parallel=“methods” 我应该如何在不运行 TestNG 的 @before 方法的情况下运行相同的测试用例? - How should I run the same test case without running the @before method from TestNG? 在Testng中使用数据提供程序和并行方法,如何在给定测试的同一线程中在方法之前,方法之后和测试中运行? - Using data-provider and parallel in Testng, how to run before method, after method and test in same thread for a given test.? 使每个测试方法在其自己的测试 class 和 TestNG 实例中运行? - Making each test method run in its own instance of a test class with TestNG? 如何作为 TESTNG 测试文件运行 - How to Run as a TESTNG test file 在testng框架中的每种测试方法之后进行清理 - Cleanup after each test method in testng framework 所有测试套件的TestNG运行方法一次 - TestNG run method once for all test suite 使用jar /无可运行方法运行testNG测试套件 - Run a testNG test suite with a jar / no runnable method 如何在每个@Test之前运行@BeforeClass方法 - How to run @BeforeClass method before each @Test Junit-每次测试结束时的方法 - Junit - method at the end of each test
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM