简体   繁体   中英

Java Selenium close browser after assertTrue

I have a code with many classes.
There is a class which creates the driver -

public class DriverDelegate {

    private String baseURL = "someLink";
    private WebDriver driver;
    private WebDriverWait wait;

    DriverDelegate(String url) {
        System.setProperty("webdriver.chrome.driver", "${directory}");
        driver = new ChromeDriver();
        driver.get(baseURL + url);
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
        wait = new WebDriverWait(driver, 5);
    }

    public WebDriver getDriver() {
        return driver;
    }

I create new driver for every test. And most of my lines are the ones containing assertTrue like this-

public class UserInterfaceTests extends BaseTest{


    @Test
    public void headerClicker() throws java.lang.Exception {

        //Startup
        DriverDelegate driverDelegate = new DriverDelegate("url");
        WebDriver driver = driverDelegate.getDriver();

        //Some random assertTrue
        assertTrue("Test(HeaderClicker) - NoSuchElementException click", TestHelper.headerClicker(schedule, driver));

        //I hope that it is not neccessary to put up all helper classes like TestHelper or BaseTest

Now I launch my tests from a class called Startup -

public class Startup{
    @Test
    public void HeaderClicker() throws Exception{ UserInterfaceTests UI = new UserInterfaceTests(); UI.headerClicker();}

My question here is how to close the browser after the assertTrue fails. Things like @AfterTest, @AfterSuite etc do not work because other methods can not use the same driver that was used in the test.
Any ideas?

Ok there are a few things I want to touch on here. First off, @shutdown -h now is correct in their comment that you shouldn't be programmatically creating test classes and running their @Test methods yourself. Let the test running framework handle that (eg TestNG, JUnit, etc).

To the point of your actual question, though, is that you want pre-test and post-test methods to handle behavior that occurs before and / or after your actual test method. For these to work, though, you need to let the test framework handle the running of the tests. You mentioned @AfterTest and @AfterSuite as not being correct for your use case, though not for the reason you specified (entirely). @AfterTest in TestNG only is executed once after all the test methods in all the classes inside of a <test> node specified in a suite. @AfterSuite is only executed once after all the test methods in the entire suite. What you are looking for is the @AfterMethod annotation.

Example:

public class FooTest {

    private DriverDelegate driver;

    @BeforeMethod
    public void setup() {
        try {
            driver = new DriverDelegate("url");
        } catch (Exception ignore) { }
    }

    @AfterMethod
    public void tearDown() {
        try {
            driver.quit();
        } catch (Exception ignore) { }
        driver = null;
    }

    @Test
    public void foo() {
        // do test stuff
    }
}

In the above code, when TestNG runs this test class, each method annotated with @Test in this class will have a corresponding @BeforeMethod execution that initializes the driver and an @AfterMethod that closes the driver even if the test fails. Couple of points to make about this type of setup with TestNG:

(1) TestNG does not create separate instances of the test class so if you save state on the class object then you cannot run the test methods themselves in parallel within a class since you would have multiple methods trying to create new drivers and save them to the same variable, corrupting the state of the other tests that are running. You can run with parallel mode of per class (eg have 5 threads, each running a separate test class at the same time).

(2) Why did I wrap the @BeforeMethod and @AfterMethod bodies in a try-catch block? Because TestNG takes a fail quickly on configuration method exceptions and can cause other tests that haven't run yet to be skipped so you need to deal with any code that could possibly fail. By wrapping the creating and closing of the web driver you can ignore the error and continue on running other tests. If the driver fails to be created, for instance, the driver variable will be null and that @Test method will fail but others might succeed. Ideally, you should probably have some logging of the exception so that you can investigate why the driver failed to be created, for instance.

Also, if you need to use a driver in many test classes, you can make a base class that does the creation of the driver along with the closing of it after each method and have your test classes extend that. If you have a class with a method annotated with @Test on it, it will run any @BeforeMethod methods on that test class AND on all of the super classes as well. There is guaranteed ordering of the methods between classes (though not if you have multiple @BeforeMethod methods in the same class).

public abstract class A {
    @BeforeMethod
    public void setupA() { }
}

public class B extends A {
    @BeforeMethod
    public void setupB() { }

    @Test
    public void foo() { }
}

In the above, when foo is run, it will have run first setupA and then setupB . After methods work in the same way, but in the reverse order.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM