0
votes

ExtentReports report;
ExtentTest logger;
Code runs correct for 1 class but throws null pointer exception for 2nd class when I use Extent report
1. I initialized in @BeforeSuite
2. Then Initialized in @BeforeMethod
3. In testng.xml there are 2 classes Class1 & Class2
4. On execution of testng.xml - All @Test of class1 runs completely but Class2 throws null pointer exception error when it reads in BeforeMethod(Initialized as mentioned in step2)

  1. Extent report has been initialized in Testbase class and created getter for it so that other class can read it
    Note: When I change BeforeSuite to BeforeClass i.e initialization of is done in BeforeClass then It runs fine but it produces extent report of only class1.

Also I am using Aftermethod to Flush the report and quit driver. Any solution to get rid of this null pointer exception

Below is the complete code
1. TestBase Class

package sampletestproject;

import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import 
 org.openqa.selenium.chrome.ChromeDriver;
import 
org.openqa.selenium.firefox.FirefoxDriver;
import 
org.openqa.selenium.support.PageFactory;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeSuite;



public class TestBasee {
    private ExtentReports report;   
    public WebDriver driverObj;
    public Homepagee homeObj;

@BeforeSuite (alwaysRun = true)
public void beforeTest(){
    System.out.println("In @BeforeSuite");
    report = new ExtentReports("G:\\ExtentReport"+fn_GetTimeStamp()+".html");
    System.out.println("Out @BeforeSuite");
}



@AfterClass(alwaysRun = true)
public void tearDown(ITestContext context) throws IOException, InterruptedException{
    System.out.println("@AfterClass In tear down");
    ITestNGMethod[] tngMethods  = context.getAllTestMethods();
    int i=1;
    for(ITestNGMethod tng: tngMethods){         
        String methodName = "Method"+i+": "+ tng.getMethodName();
        i++;
        System.out.println(methodName);
    }
}
public static String fn_GetTimeStamp() {
    DateFormat DF = DateFormat.getDateTimeInstance();
    String DateVal = DF.format(new Date());
    DateVal = DateVal.replaceAll("/", "_");
    DateVal = DateVal.replaceAll(",", "_");
    DateVal = DateVal.replaceAll(":", "_");
    DateVal = DateVal.replaceAll(" ", "_");
    return DateVal;
}
                /******************** Open Site **************************/
public Homepagee gm_OpenApp(String BrowserName, String URL) throws Exception {
    System.out.println("In gm_OpenAp Method");
    System.out.println(BrowserName+" -- "+URL);     
    gm_LaunchBrowser(BrowserName);
    Thread.sleep(2000);
    gm_OpenURL(URL);
    Thread.sleep(2000);
    homeObj = PageFactory.initElements(driverObj, Homepagee.class);
    return homeObj;
}
public void gm_OpenURL(String URL) {
    driverObj.get(URL);
}   
public void gm_LaunchBrowser(String browserName) throws Exception{
    // Launch Chrome browser
     if (browserName.equalsIgnoreCase("CH") == true) {
         System.setProperty("webdriver.chrome.driver", "MasterFiles\\Drivers\\ChromeDriver\\Chromedriver_win32_v2.38\\chromedriver.exe");
        driverObj = new ChromeDriver();
     }
     // Launch Firefox browser
     else if (browserName.equalsIgnoreCase("FF") == true) {
         System.setProperty("webdriver.gecko.driver", "MasterFiles\\Drivers\\GeckoDriver\\64Bit\\v20\\geckodriver.exe");
         driverObj = new FirefoxDriver();
     }
     driverObj.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
     driverObj.manage().timeouts().pageLoadTimeout(250, TimeUnit.SECONDS);
     driverObj.manage().window().maximize();

}
                            /****************TAKE SCREENSHOT*****************/
public String gm_setScreenshotPath_forExtentReporting(String elementName, String resultStatus) {
    System.out.println("In gm_setScreenshotPath_forExtentReporting");
    System.out.println(elementName + "--" + resultStatus);
    String screenshotPath = "G:\\QA\\AutomationTools\\Selenium\\WorkspaceMars1\\1.2hp.com.automationprac\\TestReports\\ExtentReport\\Screenshots\\"+ resultStatus + "\\" + elementName + "_" + fn_GetTimeStamp() + ".png";
    return screenshotPath;
}
public void gm_TakeSnapshot(String destFilePath) throws IOException, InterruptedException {
    TakesScreenshot tss = (TakesScreenshot) driverObj;
    File srcfileobj = tss.getScreenshotAs(OutputType.FILE);
    File destFileObj = new File(destFilePath);
    FileUtils.copyFile(srcfileobj, destFileObj);

}
public ExtentReports getReport() {
    return report;
}


public void setReport(ExtentReports report) {
    this.report = report;
  }

  }

2. SignIn -Page Object

package sampletestproject;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class SignInPagee extends TestBasee{
@FindBy(xpath = "//div[@id = 'center_column']/h1")
 public static WebElement PageHeading_SignIn_txt;

 @FindBy(xpath = "//h3[contains(text(), 'Already registered?')]")
 public static WebElement SectionHeading_SignIn_txt;


    public SignInPagee(WebDriver driverObj){
        this.driverObj = driverObj;      
    }

  }

3. Homepage - PageObject

package sampletestproject;
import java.io.IOException;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.TimeUnit; 
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import 
org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.FindBy;
import 
org.openqa.selenium.support.PageFactory;
import 
org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;
import 
import com.google.common.base.Function;

public class Homepagee extends TestBasee {


public Homepagee(WebDriver driverObj){
      this.driverObj = driverObj;
  }

 public SignInPagee navigateToSignInPage(){
     System.out.println("In navigateToSignInPage"); 
     driverObj.navigate().to("http://automationpractice.com/index.php?controller=authentication&back=my-account");
     SignInPagee signInPageObj = PageFactory.initElements(driverObj, SignInPagee.class);
     return signInPageObj;
   }


}

4. HomepageTest -Testpage

package sampletestproject;
import java.lang.reflect.Method;
import org.testng.Assert;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
import com.relevantcodes.extentreports.ExtentReports;
import com.relevantcodes.extentreports.ExtentTest;
import com.relevantcodes.extentreports.LogStatus;

public class HomepageeTest extends TestBasee {
    //ExtentReports report;
    ExtentTest logger;
    String elementName;
    String Comment;
    String actualResult;
    String expectedResult;



    @BeforeMethod(alwaysRun = true)
    @Parameters({ "Browser", "URL"})
    public void getBrowser(Method method, String Browser, String URL) throws Exception{
        logger = getReport().startTest((this.getClass().getSimpleName()+"::"+method.getName()), method.getName());
        logger.assignAuthor("VK");
        logger.assignCategory("HomePage - Smoketesting and TextTesting--Live");
        homeObj = gm_OpenApp(Browser, URL);             

    }
     @AfterMethod (alwaysRun = true)
        public void publishReport_SIP(ITestResult result) throws Exception{
            System.out.println("publishReport_SIP");
            String resultStatus = null;         
            if(result.getStatus() == ITestResult.FAILURE){              
                resultStatus = "FAILED"; 
                String screenshot_Path = gm_setScreenshotPath_forExtentReporting(elementName, resultStatus);            
                gm_TakeSnapshot(screenshot_Path);               
                String image = logger.addScreenCapture(screenshot_Path);
                logger.log(LogStatus.FAIL, Comment, image);
            }else{              
                resultStatus = "PASSED";                
                String screenshot_Path = gm_setScreenshotPath_forExtentReporting(elementName, resultStatus);
                gm_TakeSnapshot(screenshot_Path);
                System.out.println("screenshot_Path: "+screenshot_Path);
                String image = logger.addScreenCapture(screenshot_Path);
                logger.log(LogStatus.PASS, Comment, image);
            }
            getReport().endTest(logger);
            getReport().flush();
            System.out.println("closing now_SIP.");
            driverObj.quit();
        }       

//"********Validation of SignIn Link********");
@Test(priority=0, groups = {"Smoke"})   
public  void validateHeaderSignInLink_HP() throws Exception{        
    System.out.println("In validateHeaderSignInLink Method_HP"); 
    elementName = "SignInLink";
    Comment = "validateHeaderSignInLink";
    actualResult = "http://automationpractice.com/index.php?controller=authentication&back=my-account";
    expectedResult = "http://automationpractice.com/index.php?controller=authentication&back=my-account";
    Assert.assertEquals(actualResult, expectedResult);
    System.out.println("Out  of validateHeaderSignInLink method_HP");
}       

//"********Validation of GetSavingNow Button********");
@Test (priority = 1, groups = {"Smoke"})
public  void validateGetSavingNowButton_HP() throws Exception{
    System.out.println("In validateGetSavingNowButton Method_HP");
    elementName = "GETSAVINGSNOWButton";        
    Comment = "validateGetSavingNowButton"; 
    expectedResult = "http://automationpractice.com/index.php";
    actualResult = "http://automationpractice.com/index.php";
    Assert.assertEquals(actualResult, expectedResult);      
    System.out.println("Out  of validateGetSavingNowButton method_HP");
}   

@Test (priority = 2, groups = {"UITest"})
//"********Validation of SearchBox********");
public  void validateSearchField_HP() throws Exception{
    System.out.println("In validateSearchField Method_HP");     
    elementName = "FadedShortSleeveTshirts_lnktxt";     
    Comment = "validateSearchField";        
    actualResult = "Faded Short Sleeve T-shirtss";  //Just to produce a failed result
    expectedResult = "Faded Short Sleeve T-shirts";
    Assert.assertEquals(actualResult, expectedResult);
    System.out.println("Out  of validateSearchField method_HP");
}


 @Test (priority = 3, enabled = true, groups = {"Smoke", "UITest"})
//"********Validation of Slider1********");  
public  void validateHomepageSlider1_HP() throws Exception{
    System.out.println("In validateHomepageSlider1 Method_HP"); 
    elementName = "Homepage Slider1";
    Comment = "validateHomepageSlider1";
    actualResult =  "https://www.prestashop.com/en?utm_source=v16_homeslider";
    expectedResult = "https://www.prestashop.com/en?utm_source=v16_homeslider";
    Assert.assertEquals(actualResult, expectedResult);  
    System.out.println("Out  of validateHomepageSlider1 method_HP");

    }   

  }

5. SignIntest Class- Testpage
package sampletestproject;

import java.lang.reflect.Method;

import org.testng.Assert;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
import 
com.relevantcodes.extentreports.ExtentTest;
import 
com.relevantcodes.extentreports.LogStatus;

public class SignInnTest extends TestBasee{



SignInPagee lognObj;    
ExtentTest logger;
String elementName;
String Comment;
String expectedResult;
String actualResult;

@BeforeMethod(alwaysRun = true)
@Parameters({ "Browser", "URL"})
public void getBrowser(Method method, String Browser, String URL) throws Exception{
    logger = getReport().startTest((this.getClass().getSimpleName()+"::"+method.getName()), method.getName());
    logger.assignAuthor("VK");
    logger.assignCategory("SignInpage - Smoketesting and TextTesting--Live");
    homeObj = gm_OpenApp(Browser, URL);             
    lognObj = homeObj.navigateToSignInPage();           
}

 @AfterMethod (alwaysRun = true)
    public void publishReport_SIP(ITestResult result) throws Exception{
        System.out.println("publishReport_SIP");
        String resultStatus = null;         
        if(result.getStatus() == ITestResult.FAILURE){              
            resultStatus = "FAILED"; 
            String screenshot_Path = gm_setScreenshotPath_forExtentReporting(elementName, resultStatus);            
            gm_TakeSnapshot(screenshot_Path);               
            String image = logger.addScreenCapture(screenshot_Path);
            logger.log(LogStatus.FAIL, Comment, image);
        }else{              
            resultStatus = "PASSED";                
            String screenshot_Path = gm_setScreenshotPath_forExtentReporting(elementName, resultStatus);
            gm_TakeSnapshot(screenshot_Path);
            System.out.println("screenshot_Path: "+screenshot_Path);
            String image = logger.addScreenCapture(screenshot_Path);
            logger.log(LogStatus.PASS, Comment, image);
        }
        getReport().endTest(logger);
        getReport().flush();
        System.out.println("closing now_SIP.");
        driverObj.quit();
    }        
@Test (priority = 0, groups = {"Smoke""})
public  void validateSignInPage_PageHeading_SIP() throws Exception{
    System.out.println("In validateSignInPage_PageHeading Method_SIP");                 
    elementName = "SignIn_PageHeading_txt";     
    Comment = "validatePageHeading_SignInpage";     
    actualResult =  "AUTHENTICATION";           
    expectedResult = "AUTHENTICATION";
    Assert.assertEquals(actualResult, expectedResult);  //Here test will pass
    System.out.println("Out  of validateSignInPageHeading method_SIP");
}   

@Test (groups = {"UITest"}, dependsOnMethods = { "validateSignInPage_PageHeading_SIP" })
public  void validateSignInPage_SignInSectionHeading_SIP() throws Exception{
    System.out.println("In validateSignInPage_SignInSectionHeading Method_SIP");        
    elementName = "SignInPage_SignInSectionHeading_txt";        
    Comment = "validateSectionHeading_SignInpage";      
    actualResult =  "ALREADY REGISTERED1?"; 
    expectedResult = "ALREADY REGISTERED?";
    Assert.assertEquals(actualResult, expectedResult); //Here Test will fail as actual not equal to expected
    System.out.println("Out  of validateSignInPage_SignInSectionHeading method_SIP");
     }  
 }

6.testng.xml suite name="Test" parallel = "tests" thread-count = "1">

<test name="CHTest"  >   
    <parameter name="Browser" value="CH" ></parameter>
    <parameter name="URL" value="http://automationpractice.com/index.php"></parameter>          
      <groups><run>         
            <include name="Smoke"/>
            <include name="UITest"/>                 
        </run></groups>             
    <classes>
        <class name= "sampletestproject.SignInnTest" /> 
        <class name= "sampletestproject.HomepageeTest"/>
    </classes></test></suite>
2
You've posted way too much code. You should spend some time taking things apart and simplifying to narrow down the issue. Once you've done that, if you still can't find the issue then come back and edit this question with a minimal reproducible example. - JeffC
Similar kind of query has been asked earlier but answers were not useful may be because of lack of clarity. so I have posted code of all 5 classes with minimum amount of code (only required ones)so that one can regenerate the issue that I am facing.. this just requires creating 5 classes in eclipse and copy pasting these codes, - Vikash Kumar

2 Answers

3
votes

I would say it's better to use a threadlocal here or an implementation similar to for managing tests and similar one for ExtentReports:

https://github.com/anshooarora/extentreports-java/blob/master/src/test/java/com/aventstack/extentreports/common/ExtentTestManager.java

Also, if you see the examples section of the docs, you already have a barebones ExtentTestNGReportBuilder example which you can use without creating any custom code like here.

The issue you are facing is due to pricinciples of Java and managaging instances than of ExtentReports. If you want a single report for all your classes then make sure there is always 1 instance only for the entire run. Prevent any behavior which recreates the instances which in your case happens - each class resets the report variable thus resetting the ExtentReports instance.

Moreover, I would recommend using ITestListener in such cases and an example of that is shown below so to separate reporting from your test code:

public class ExtentITestListener
implements ITestListener {

private static final ExtentReports EXTENT = Extent.getInstance();

private static ThreadLocal<ExtentTest> methodTest = new ThreadLocal<ExtentTest>();
private static ThreadLocal<ExtentTest> dataProviderTest = new ThreadLocal<>();

@Override
public synchronized void onStart(ITestContext context) { }

@Override
public synchronized void onFinish(ITestContext context) {
    EXTENT.flush();
}

@Override
public synchronized void onTestStart(ITestResult result) {      
    String methodName = result.getMethod().getMethodName();
    if (result.getParameters().length>0) {
        if (methodTest.get() != null && methodTest.get().getModel().getName().equals(methodName)) { } 
        else {
            createTest(result);
        }
        String paramName = Arrays.asList(result.getParameters()).toString();
        ExtentTest paramTest = methodTest.get().createNode(paramName);
        dataProviderTest.set(paramTest);
    } else {
        createTest(result);
    }
}

private void createTest(ITestResult result) {
    String methodName = result.getMethod().getMethodName();
    ExtentTest test = EXTENT.createTest(methodName);
    methodTest.set(test);

    String[] groups = result.getMethod().getGroups();
    if (groups.length > 0) {
        Arrays.asList(groups)
            .forEach(x -> methodTest.get().assignCategory(x));
    }
}

@Override
public synchronized void onTestSuccess(ITestResult result) {
    getTest(result).pass("Test passed");
}

private ExtentTest getTest(ITestResult result) {
    ExtentTest t = result.getParameters() != null && result.getParameters().length>0
            ? dataProviderTest.get()
            : methodTest.get();
    return t;
}

@Override
public synchronized void onTestFailure(ITestResult result) {
    getTest(result).fail(result.getThrowable());
}

@Override
public synchronized void onTestSkipped(ITestResult result) {
    getTest(result).skip(result.getThrowable());
}

@Override
public synchronized void onTestFailedButWithinSuccessPercentage(ITestResult result) { }

}
1
votes

I have also faced the same issue while executing the 2 classes from the testNG.xml file. I found that the ExtentReport variable gets null after running @AfterMethod annotation that's why it's returning null pointer exception while running test cases from another class.

The solution that worked for me is by making ExtentReport variable as Static so that it creates a single copy of extent report variable and while running multiple classes you won't get that error.

For ex: static ExtentReports reports;

Let me know if the issue still persists.