I'm trying to use @beforeSuite and @AfterSuite to run my test in one browser instance. however it run the first the first test class but fail with null pointer exception when it the second class.
Here is my code below:
LaunchBrowser.java class
public class LaunchBrower {
protected WebDriver driver;
public WebDriver getDriver() {
return driver;
}
@Parameters({ "browserType", "appURL" })
@BeforeSuite
public void setUp(@Optional String browsertype, @Optional String appURL) {
System.out.println("Launching google chrome with new profile..");
driver = getBrowserType(browsertype);
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
driver.manage().window().maximize();
driver.navigate().to(appURL);
}
private WebDriver getBrowserType(String browserType) {
if (driver == null ) {
if (browserType.equalsIgnoreCase("chrome")) {
return new ChromeDriver();
}
else if (browserType.equalsIgnoreCase("InternetExplorer")) {
return new InternetExplorerDriver();
}
}
return driver;
}
@AfterSuite
public void tearDown() {
if (driver != null)
driver.quit();
}
}
LoginPageTest class
public class LoginPageTest extends LaunchBrower {
protected WebDriver driver;
private LoginPage loginpage;
private MyProfile profilepage;
Logger log = Logger.getLogger("Results:");
@BeforeClass(alwaysRun = true)
public void setUp() {
loginpage = PageFactory.initElements(getDriver(), LoginPage.class);
//loginpage = new LoginPage(driver);
//driver=getDriver();
}
@Test(groups = "LoginPage")
public void verifyLogin() throws InterruptedException {
//LoginPage login = new LoginPage(driver);
System.out.println("Sign In functionality details...");
//System.out.println("Sign In functionality details seee...");
Thread.sleep(10000);
//login.enterUserName("11111111");
Assert.assertEquals("11111111",loginpage.enterUserName("11111111"));
log.debug("Correct Username Pass");
//System.out.println("Correct username...");
Assert.assertEquals("fe9245db",loginpage.enterPassword("fe9245db"));
log.debug("Correct Password Pass");
loginpage.clickOnLogin();
log.debug("Login Pass");
}
}
MyProfileTest java class
public class MyProfileTest extends LaunchBrower {
protected WebDriver driver;
private MyProfile profilepage;
@BeforeClass(alwaysRun = true)
public void setUp() {
profilepage = PageFactory.initElements(getDriver(), MyProfile.class);
//driver=getDriver();
}
@Test(groups = "Myprofile")
public void verifyMyprofile() throws InterruptedException {
System.out.println("My profile test...");
//MyProfile profile = new MyProfile(driver);
profilepage.ClickToggleLink();
profilepage.ClickMyProfile();
}
}
The problem lies in your test code. @BeforeSuite
is designed in TestNG to be invoked only once per <suite>
. You are combining that logic along with inheritance and then relying on the @BeforeSuite
method to initialize your WebDriver. So it will do it for the first class in your <suite>
by from the second class onwards TestNG is not going to be invoking the @BeforeSuite
and thus your second class onwards you start seeing the NullPointerException
.
You should instead consider relying on a ISuiteListener
implementation as a listener and then wire it into your test execution.
Your tests would now start relying on a webdriver that is created in this manner and then work with it.
Please ensure that you are using TestNG 6.12 or higher (which at this point doesn't exist).
Here's a full fledged example that shows all of this in action.
The base class of my test classes look like below
package com.rationaleemotions.stackoverflow.qn46323434;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.annotations.Listeners;
@Listeners(BrowserSpawner.class)
public class MyBaseClass {
protected void launchPage(String url) {
RemoteWebDriver driver = BrowserSpawner.getDriver();
driver.get(url);
System.err.println("Page Title :" + driver.getTitle());
}
}
The test classes that I am using in this example look like below
package com.rationaleemotions.stackoverflow.qn46323434;
import org.testng.annotations.Test;
public class MyFirstTestCase extends MyBaseClass {
@Test
public void testGooglePage() {
launchPage("http://www.google.com");
}
@Test
public void testFaceBookPage() {
launchPage("http://www.facebook.com");
}
}
package com.rationaleemotions.stackoverflow.qn46323434;
import org.testng.annotations.Test;
public class MySecondTestCase extends MyBaseClass {
@Test
public void testHerokkuPage() {
launchPage("https://the-internet.herokuapp.com/");
}
@Test
public void testStackOverFlowPage() {
launchPage("http://stackoverflow.com/");
}
}
The ISuiteListener implementation looks like below
package com.rationaleemotions.stackoverflow.qn46323434;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.ISuite;
import org.testng.ISuiteListener;
import org.testng.ITestResult;
import org.testng.Reporter;
public class BrowserSpawner implements ISuiteListener {
private static final String DRIVER = "driver";
@Override
public void onStart(ISuite suite) {
RemoteWebDriver driver;
String browserType = suite.getParameter("browserType");
switch (browserType) {
case "chrome":
driver = new ChromeDriver();
break;
default:
driver = new FirefoxDriver();
}
suite.setAttribute(DRIVER, driver);
}
@Override
public void onFinish(ISuite suite) {
Object driver = suite.getAttribute(DRIVER);
if (driver == null) {
return;
}
if (!(driver instanceof RemoteWebDriver)) {
throw new IllegalStateException("Corrupted WebDriver.");
}
((RemoteWebDriver) driver).quit();
suite.setAttribute(DRIVER, null);
}
public static RemoteWebDriver getDriver() {
ITestResult result = Reporter.getCurrentTestResult();
if (result == null) {
throw new UnsupportedOperationException("Please invoke only from within an @Test method");
}
Object driver = result.getTestContext().getSuite().getAttribute(DRIVER);
if (driver == null) {
throw new IllegalStateException("Unable to find a valid webdriver instance");
}
if (! (driver instanceof RemoteWebDriver)) {
throw new IllegalStateException("Corrupted WebDriver.");
}
return (RemoteWebDriver) driver;
}
}
The suite xml file that I am using looks like below
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="46323434_Suite" parallel="false" verbose="2">
<parameter name="browserType" value="chrome"/>
<test name="46323434_test1">
<classes>
<class name="com.rationaleemotions.stackoverflow.qn46323434.MyFirstTestCase"/>
</classes>
</test>
<test name="46323434_test2">
<classes>
<class name="com.rationaleemotions.stackoverflow.qn46323434.MySecondTestCase"/>
</classes>
</test>
</suite>
When you run this the output would look like below
...
... TestNG 6.12 by Cédric Beust (cedric@beust.com)
...
Starting ChromeDriver 2.32.498537 (cb2f855cbc7b82e20387eaf9a43f6b99b6105061) on port 45973
Only local connections are allowed.
log4j:WARN No appenders could be found for logger (org.apache.http.client.protocol.RequestAddCookies).
log4j:WARN Please initialize the log4j system properly.
Sep 20, 2017 10:36:41 PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: OSS
Page Title :Facebook – log in or sign up
Page Title :Google
PASSED: testFaceBookPage
PASSED: testGooglePage
===============================================
46323434_test1
Tests run: 2, Failures: 0, Skips: 0
===============================================
Page Title :The Internet
Page Title :Stack Overflow - Where Developers Learn, Share, & Build Careers
PASSED: testHerokkuPage
PASSED: testStackOverFlowPage
===============================================
46323434_test2
Tests run: 2, Failures: 0, Skips: 0
===============================================
===============================================
46323434_Suite
Total tests run: 4, Failures: 0, Skips: 0
===============================================
The most important things to remember here are :
ISuiteListener
implementation.<suite>
) you will never be able to run your tests in parallel. All of your tests should strictly run in sequential manner.@Test
methods either crash the browser (or) cause the browser instance to be cleaned up (this is applicable when you are dealing with a Grid setup wherein you probably endup leaving the browser idle for sometime causing the node to cleanup the browser from the server side). If you cause any of this, then your tests are going to fail with unexpected results.