Reputation: 441
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
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
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
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
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