Prakash P
Prakash P

Reputation: 441

@AfterTest selenium annotation getting executed before all the @Test's are executed

I have worked on Selenium and TestNG. But I am not an expert. I tried searching a suitable answer for this but could not find. Hence requesting help.

I have a initialization class as below.

public class Initialization {

    private static Logger logger = Logger.getLogger(Initialization.class);
    private WebDriver driver;

    @BeforeTest
    public void intiDriver() throws MalformedURLException {
        logger.debug("Creating driver");
        DesiredCapabilities dcap = DesiredCapabilities.firefox();
        driver = new RemoteWebDriver(new URL("http://127.0.0.1:4444/wd/hub"), dcap);
        logger.debug("Driver created");
    }

    @AfterTest
    public void closeDriver(){
        logger.debug("Quitting driver");
        if(driver != null){
            driver.close();
            driver.quit();
            logger.debug("Driver destroyed");
        }
    }

    public WebDriver getDriver() {
        return driver;
    }
}

And then I have 2 test case class file which extends the above class file (as shown below)

public class SampleTestCase1 extends Initialization {

    @Test
    public void sampleTest1(){
        System.out.println("getDriver1: "+ getDriver());
        getDriver().get("http://www.google.com");
    }

    @Test
    public void sampleTest2(){
        System.out.println("getDriver2: "+ getDriver());
        getDriver().get("http://www.bing.com");
    }
}

public class SampleTestCase2 extends Initialization {

    @Test
    public void sampleTest3(){
        System.out.println("getDriver3: "+ getDriver());
        getDriver().get("https://en.wikipedia.org/wiki/Main_Page");
    }

    @Test
    public void sampleTest4(){
        System.out.println("getDriver4: "+ getDriver());
        getDriver().get("http://www.rediff.com/");
    }
}

I am observing that sampleTest3 and sampleTest4 testcases are not being executed because getDriver() is returning null. I believe the driver instance is getting destroyed after I execute sampleTest1 and smapleTest2. I have used @afterTest annotation, hence ideally the driver instance should be destroyed after all the @Test's are executed.

I don't what is going wrong. Can somebody help?.

Stack Trace:

java.lang.NullPointerException
    at Sample.SampleTestCase2.sampleTest3(SampleTestCase2.java:16)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:86)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:643)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:820)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1128)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
    at org.testng.TestRunner.privateRun(TestRunner.java:782)
    at org.testng.TestRunner.run(TestRunner.java:632)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:366)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:361)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:319)
    at org.testng.SuiteRunner.run(SuiteRunner.java:268)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1244)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1169)
    at org.testng.TestNG.run(TestNG.java:1064)
    at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:74)
    at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:121)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

Upvotes: 4

Views: 6205

Answers (4)

StrikerVillain
StrikerVillain

Reputation: 3776

Answer continued....

If you would like to open the browser and close it only once Make the driver and the getDriver() method static in the initialization code.

public class Initialization {
private static WebDriver driver;

    @BeforeTest
    public void intiDriver() {
        driver = new FirefoxDriver();
        System.out.println("start");
    }

    @AfterTest
    public void closeDriver() {
        driver.quit();
        System.out.println("stop");
    }

    public static WebDriver getDriver() {
        return driver;
    }
}

TestNG.xml

<suite name="Suite1" verbose="1">
    <test name="Sample Test">
        <classes>
            <class name="Sample.SampleTestCase1" />
            <class name="Sample.SampleTestCase2" />
        </classes>
    </test>
</suite>

If you are Ok with opening the browser multiple times (1 browser/Test class), you can keep the original Initialization class (no need of static drivers) and modify only the TestNG XML file to contain 2 tests.

<suite name="Suite1" verbose="1">
    <test name="Sample Test1">
        <classes>
            <class name="Sample.SampleTestCase1" />
        </classes>
    </test>
    <test name="Sample Test2">
        <classes>
            <class name="Sample.SampleTestCase2" />
        </classes>
    </test>
</suite>

Upvotes: 0

optimistic_creeper
optimistic_creeper

Reputation: 2799

You can do either:

  • Change your annotations to @BeforeClass and @AfterClass respectively

  • Change your xml. Put your classes under test tag

Hope, you understand what I mean.

Upvotes: 1

StrikerVillain
StrikerVillain

Reputation: 3776

What you have to understand is the TestNG execution order when you execute the tests using the xml file in the following configuration

<suite name="Suite1" verbose="1">
    <test name="Sample Test">
        <classes>
            <class name="Sample.SampleTestCase1" />
            <class name="Sample.SampleTestCase2" />
        </classes>
    </test>
</suite>

Order:

@BeforeTest in SampleTestCase1 extends Initialization
    sampleTest1
    sampleTest2
    sampleTest3
    sampleTest4
@AfterTest in SampleTestCase1 extends Initialization

Ignored:

@BeforeTest in SampleTestCase2 extends Initialization
@AfterTest in SampleTestCase2 extends Initialization

This is because you have added SampleTestCase1 and SampleTestCase2 as <classes> to the <test> in the TestNG xml file. This mean SampleTestCase1 and SampleTestCase2 are part of a single test called Sample Test. Eventhough both classes extends Initialization class (you would expect @BeforeTest and @AfterTest getting called for each test class), TestNG only sees 1 @BeforeTest and 1 @AfterTest and 4 test methods.

SampleTest1 and SampleTest2 gets the driver because @BeforeTest in SampleTestCase1 extends Initialization is invoked. sampleTest3 and sampleTest4 methods getDriver() method returns null because @BeforeTest in SampleTestCase2 extends Initialization is never invoked.

If you add a sysout in the @BeforeTest to print "start" and @AfterTest to print "stop" you would find the following in the console proving the above point.

start
getDriver1: FirefoxDriver: firefox on WINDOWS (8573d6f7-fa66-45bc-9754-1145f5834b82)
getDriver2: FirefoxDriver: firefox on WINDOWS (8573d6f7-fa66-45bc-9754-1145f5834b82)
getDriver3: null
getDriver4: null
stop

===============================================
Suite1
Total tests run: 4, Failures: 2, Skips: 0
===============================================

I will add one of the many solutions to make it work as a separate answer as this answer has gotten pretty lengthy!!

Upvotes: 0

juherr
juherr

Reputation: 5740

TestNG is not JUnit. Don't missmatch @BeforeTest/AfterTest and @BeforeMethod/AfterMethod.

@BeforeTest: The annotated method will be run before any test method belonging to the classes inside the tag is run.

@AfterTest: The annotated method will be run after all the test methods belonging to the classes inside the tag have run.

@BeforeMethod: The annotated method will be run before each test method.

@AfterMethod: The annotated method will be run after each test method.

http://testng.org/doc/documentation-main.html#annotations

Upvotes: 3

Related Questions