Null pointer exception due to driver instance is null in onTestFailureMethod - selenium-webdriver

Need help on - I am getting null pointer exception in onTestFailure method. If any of my #Test method fails control goes to onTestFailure but driver is null in that method. my code is like -
import statements...
#Listeners(ScreenShot.class)
public class ScreenShot implements ITestListener{
WebDriver driver;
#BeforeClass
public void launch(){
System.setProperty("webdriver.ie.driver", "D:\\Jars\\Drivers\\IEDriverServer.exe");
driver = new InternetExplorerDriver();
driver.get("url");
}
#Test
public void test1(){
//driver.findElement(By.id("Email")).sendKeys("E#E.COM");
System.out.println("Method1 begins");
//some code here - exception occurs here
System.out.println("Method ended");
}
public void onTestFailure(ITestResult result){
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); //Getting exception here as driver is null
try {
FileUtils.copyFile(scrFile, new File("C:\\snaps\\"+result.getMethod().getMethodName()+".png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
i am running this class by right click->run as testng.

The reason you are getting a NullPointerException is because Testng creates a new instance of each listener. So that new instance has driver not initialized.
In your case, the object of Screenshot class running the #Test method and the instance of the Screenshot class as a listener being invoked by TestNG is different.
There are couple of ways to solve this.
Move the code from onTestFailure to #AfterMethod with the ITestResult as the method argument. Work on the result data to take screenshot.
#AfterMethod
public void afterMet(ITestResult res){
if(res.isSuccess())
Make the driver as a global static. - if you plan to run only sequential tests
Consider threadlocal if you plan to run parallely.

Related

Selenium Webdriver Testng : How to fail a test in assertion and send meaningful message in a report instead of "Nosuchelementexception" trace

Their are numerous resources on internet but I couldn't find a simple answer to my problem.
I want my test case to fail and report a one liner meaningful message instead of full stack trace.
I tried using try, catch, if, else but I want my test to fail not to pass and throw message.
Scenario - Load url, if url doesn't load throw error and abort test and move to next iteration of loading next url
Any solution ?
You can try... try catch
try {
doStuff();//this code is failing
}
catch (YourExpectedException e){ //catch the correct exception here
//this passes your custom message AND the caught exception
//should also stop the test
throw new AssertionError("This is my custom message", e);
}
There are two ways how to do it. I would like to suggest you the most simple and beautiful ways.
1) Checking exception and if exception on of you specify you will execute some code or do something. Here is the example:
#AfterMethod
public void afterMethod(ITestResult result) throws IOException {
Throwable exception = result.getThrowable();
if (exception instanceof org.openqa.selenium.TimeoutException
||
exception instanceof org.openqa.selenium. NoSuchElementException) {
Assert.fail("Some message or code");
}
}
2)
You can implement WebDriverEventListener in your project.
What it means?
It means that WebDriver allow to execute some logic before and after some events. You can add try-catch in the implementation of methods.
Example:
#Override
public void beforeFindBy(By by, WebElement webElement, WebDriver webDriver) {
// your code
}
#Override
public void afterFindBy(By by, WebElement webElement, WebDriver webDriver) {
// your code
}
#Override
public void beforeClickOn(WebElement webElement, WebDriver webDriver) {
// your code
}
#Override
public void afterClickOn(WebElement webElement, WebDriver webDriver) {
// your code
}
Here is more detail example: link

How to handle browser invocation in parallel tests using TestNG

I have been using browser invocation in #Beforeclass TestNG method using the parameter passed from testng.xml. Once the browser is invoked, I am using login test in a #BeforeMethod which is required for all the other #Tests to start. But with this setup, I am unable to run the tests in parallel. I am seeing one browser is open and login tests which is required by both tests are run in same browser and fails. All my tests are in single class file. Code structure is as below:
public class MainTest {
WebDriver driver;
BrowserFactory browser;
ReadData crmdatafile;
#BeforeClass(alwaysRun = true)
public void setup(ITestContext context) throws Exception{
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("datafile.txt").getFile());
crmdatafile = new ReadData(file.getAbsolutePath());
browser = new BrowserFactory(context.getCurrentXmlTest().getParameter("Selenium.browser"));
driver = browser.getNewBrowser();
driver.manage().deleteAllCookies();
driver.get(crmdatafile.data.get("enviornment", "url"));
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);
}
#BeforeMethod()
public void login(){
System.out.println("contains the code for login which needs to be run before every test");
}
#AfterMethod
public void afterEachTest(ITestResult result) throws IOException {
driver.close();
}
#Test
public void Test1() {
System.out.println("Will run login and next steps");
}
#Test
public void Test2() {
System.out.println("Will run login and next steps");
}
public class BrowserFactory {
private WebDriver driver;
private String browser;
public BrowserFactory(String browser) {
String brow=browser.trim().toLowerCase();
if(!(brow.equals("firefox") || brow.equals("ff") || brow.equals("internetexplorer") || brow.equals("ie") || brow.equals("chrome") || brow.equals("gc"))) {
browser="ie";
}
this.browser = browser;
}
public WebDriver getNewBrowser() {
String brow = browser.trim().toLowerCase();
if(brow.equals("firefox") || brow.equals("ff")) {
System.setProperty("webdriver.gecko.driver", "drivers\\geckodriver.exe");
DesiredCapabilities capabilities = DesiredCapabilities.firefox();
capabilities.setCapability("marionette", true);
driver = new FirefoxDriver(capabilities);
driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);
return driver;
}else if(brow.equals("internetexplorer") || brow.equals("ie")){
driver = new InternetExplorerDriver();
driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);
return driver;
}else if(brow.equals("chrome") || brow.equals("gc")){
System.setProperty("webdriver.chrome.driver", "drivers\\chromedriver.exe");
DesiredCapabilities capabilities = DesiredCapabilities.chrome();
ChromeOptions options = new ChromeOptions();
options.addArguments("test-type");
capabilities.setCapability("webdriver.chrome.binary","drivers\\chromedriver.exe");
capabilities.setCapability(ChromeOptions.CAPABILITY, options);
driver = new ChromeDriver(capabilities);
driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);
return driver;
}
return null;
}
How can I improve the above structure to run tests in parallel and using a different browser for each test?
Your test code has some issues.
You are instantiating a webdriver instance in your #BeforeClass annotated method and that is being shared by all your #Test annotated test methods. You are also invoking driver.close() in an #AfterMethod annotated method.This is a recipe for disaster because AFAIK driver.close() is equivalent to driver.quit() if you are having only one web browser instance. So what this means is that your second test method will not have a valid browser (if you are running sequentially).
If you are running in parallel, then all your test methods are going to be competing for the same browser, which is now going to cause race conditions and test failures.
You should ideally speaking move the logic of your setup() method into a listener which implements IInvokedMethodListener interface and then have this listener inject the webdriver instances into a ThreadLocal variable, which your #Test methods can then query.
You can refer to my blog post which talks in detail on how to do this.
Please check if that helps.
Here is the thing, as far as I can see you're not using annotations right and (probaly) testNG as well.
If you want to create browser instance before each test you may want to use #BeforeTest annotation. Also you may perform your test set up in this method as well. #BeforeClass annotation will be executed only once before this particular class will be executed.
It's a good idea to split tests that do different things into separate test files, case your tests do almost the same, but say params for tests are different - it's a good idea to use #DataProvider. Otherwise maybe you may want to extend your basic test with setup.
If you just want to re-execute same tests, but with different browser - consider relaunching your test job with different params or using #DataProvider as described above.
As far as I remember there are several ways to run testNG in parallel: Methods, Classes, Tests, Instances - figure out which one you need and which one works better with your setup.

Appium : NullPointerException coming

I am trying to run the below code to automate my mobile application and every thing seems OK but I am getting NullPointerException on following line:
driver.findElement(By.id("com.app.aftertax.aftertax:id/Text7"));
Here is my code:
public class Login {
public static AndroidDriver driver;
#BeforeTest
public void setUp() throws Exception {
File classpathRoot = new File(System.getProperty("user.dir"));
File app = new File("/Users/hanan/Downloads/app-at.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("deviceName", "Android Emulator");
capabilities.setCapability("platformName","Android");
capabilities.setCapability("platformVersion","4.4");
capabilities.setCapability("app-package", "com.mobikwik_new");
capabilities.setCapability("app-activity", ".MobikwikMain");
capabilities.setCapability("app-wait-activity",
".MobikwikMain");
capabilities.setCapability("appiumVersion", "1.3.7");
//capabilities.setCapability("name", methodName.getName());
capabilities.setCapability("app", app.getAbsolutePath());
new AndroidDriver( new URL("http://localhost:4723/wd/hub"),
capabilities);
}
#Test
public void apiDemo() throws InterruptedException {
Thread.sleep(10000);
WebElement login = driver.findElement(By.id("com.app.aftertax.aftertax:id/Text7"));
login.click();
}
}
If your code line is the first in the stack trace (you should add the full stacktrace to such questions), then it's the driver variable which is not initialized (==null)
It seems that you are not assigning Appium object in below code:
new AndroidDriver( new URL("http://localhost:4723/wd/hub"),
capabilities);
You should create reference variable of AppiumDriver or AndroidDriver at class level. then assign created object in reference variable like below:
driver = new AndroidDriver( new URL("http://localhost:4723/wd/hub"),
capabilities);

java.lang.NullPointerException: No API environment is registered for this thread on Unit testing

I'm trying to run a unit test on inserting records to datastore using Objectify but I'm getting java.lang.NullPointerException: No API environment is registered for this thread every time I run the test or even trying to run it on Dev server.
Create an instance of LocalServiceTestHelper initializing LocalDatastoreServiceTestConfig and call setup() before doing any Objectify calls :
public class LocalDatastoreTest {
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
#Before
public void setUp() {
helper.setUp();
}
#After
public void tearDown() {
helper.tearDown();
}
private void doTest() {
// Objectify calls will work here.
}
}
See also https://cloud.google.com/appengine/docs/java/tools/localunittesting

Getting ElementNotFound Exception in TestNG

The following code is for login and then click on Create quest Link. It does not click on the link and gives ElementNotFound exception and skips the test. It just logs in and logout. Please Help
public class Edit_Question {
WebDriver driver = new FirefoxDriver();#
BeforeTest
public void load() {
driver.get("Page url");
}
# Test
public void login() throws InterruptedException {
driver.findElement(By.id("userid")).sendKeys("4060#jhg.com");
driver.findElement(By.id("password")).sendKeys("mpcyn2");
driver.findElement(By.id("emLoginLink")).click();
Thread.sleep(10000);
}# Test
public void ques() throws InterruptedException {
//select create questions
driver.findElement(By.xpath("//xpath link")).click(); //throws ElementNotFound exception
Thread.sleep(5000);
}# Test
public void logout() {
//logout
driver.findElement(By.partialLinkText("SeeharackTest1, SherrodUATT")).click();
driver.findElement(By.id("logoutLink")).click();
}
# AfterSuite
public void close() {
driver.close();
}
}
The order of execution is not gauranteed. You need to use dependOnMethods to gaurantee order here. So ques should depend on login and logout should depend on ques to gaurantee the order of execution.
Other observations :
1. Try using #BeforeClass instead of #BeforeTest and #AfterClass instead of #AfterSuite
2. Avoid using sleeps wherever possible. Wait for a particular element instead.
3. Shouldn't this entire flow be one testcase?
Hope it helps.

Resources