How can I include a failure screenshot to the testNG report - java

currently I am taking screenshots of my test failures this way:
#AfterMethod(alwaysRun=true)
public void catchExceptions(ITestResult result){
Calendar calendar = Calendar.getInstance();
SimpleDateFormat formater = new SimpleDateFormat("dd_MM_yyyy_hh_mm_ss");
String methodName = result.getName();
if(!result.isSuccess()){
File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
try {
FileUtils.copyFile(scrFile, new File((String) PathConverter.convert("failure_screenshots/"+methodName+"_"+formater.format(calendar.getTime())+".png")));
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
Can I include my own screenshots into the TestNG report link or pic? If yes how?
All I found on that online is the FEST framework. But since I am already taking the screenshots I dont want to use another framework.

Yes, you can include the link to your screenshot in testng report.
You need to call org.testng.Reporter.log method to write the hyperlink to the testng report either by annotating your test class or parent of all testclasses with #Listeners({yourListener.class}) or by adding the listener to your testng.xml.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="default">
<listeners>
<listener class-name="ScreenshotListener" />
</listeners>
<test name="Test">
<packages>
<package name="someTests.*"/>
</packages>
</test>
</suite>
You need to first create a Listener class and add it to testng. You can get details for that from testng.org. Search for listener.
Once you create that class, you should write a method in it which overrides the ontestfailure method. The code inside this method will be executed whenever testng identifies a failure.
You can call your screenshot grabbing method and use Reporter.log to put the hyperlink to that screenshot. Then you can find this link under the failed testcases details.
import java.io.*;
import java.util.*;
import java.text.*;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.testng.*;
public class ScreenshotListener extends TestListenerAdapter {
#Override
public void onTestFailure(ITestResult result) {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat formater = new SimpleDateFormat("dd_MM_yyyy_hh_mm_ss");
String methodName = result.getName();
if(!result.isSuccess()){
File scrFile = ((TakesScreenshot)SomeStaticWebDriver.driver).getScreenshotAs(OutputType.FILE);
try {
String reportDirectory = new File(System.getProperty("user.dir")).getAbsolutePath() + "/target/surefire-reports";
File destFile = new File((String) reportDirectory+"/failure_screenshots/"+methodName+"_"+formater.format(calendar.getTime())+".png");
FileUtils.copyFile(scrFile, destFile);
Reporter.log("<a href='"+ destFile.getAbsolutePath() + "'> <img src='"+ destFile.getAbsolutePath() + "' height='100' width='100'/> </a>");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

Customizing a bit of ExtentReport can give extremely useful report having exception+screenshot captured exactly at time of test failure . Screenshot can be placed alongside exception which user can use to know what was website doing when error occurred.
Report Example
Test
#Test (enabled=true)
public void verifySearch() {
extentlogger = extent.createTest("To verify verifySearch");
//Your other code here.....
soft.assertEquals("xxx", "xxxx");
soft.assertAll();
}
AfterMethod
#AfterMethod
public void getResult(ITestResult result) throws Exception{
if(result.getStatus() == ITestResult.FAILURE)
{
extentlogger.log(Status.FAIL, MarkupHelper.createLabel(result.getThrowable() +
" - Test Case Failed", ExtentColor.RED));
try {
// get path of captured screenshot using custom failedTCTakeScreenshot method
String screenshotPath = failedTCTakeScreenshot( result);
extentlogger.fail("Test Case Failed Snapshot is below " +
extentlogger.addScreenCaptureFromPath(screenshotPath));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

Related

TESTNG | call testng.xml file from main method from inside a runnable jar

I am new to testng + maven and I have requirement to run scripts using runnable jar. The suite needs to be executed for multiple regions . The region name is passed as an argument while executing jar.
Now my requirement is to switch between multiple testng.xml files based on the region name provided.
All the testng.xml files are placed inside resource folder --> "resources/testngA.xml" and "resources/testngB.xml".
When I run the script from eclipse it works fine but when i try to execute the same through runnable.jar it shows java.io.FileNotFoundException exception . Can anyone please help me to fix this.
public class TestRunner {
static TestNG testng;
static List<String> suites;
public static void main(String[] args) {
String xmlFileName = "";
List<XmlSuite> suite;
String region = arg[0];
try
{
if(region.equals("A")){
xmlFileName = "resources/A_TestNG.xml";
}else if(region.equals("B")){
xmlFileName = "resources/B_TestNG.xml";
}else{
System.out.println("No matching region found")
}
suite = (List <XmlSuite>)(new Parser(xmlFileName).parse());
testng.setXmlSuites(suite);
testng.run();
}
catch (ParserConfigurationException e)
{
e.printStackTrace();
}
catch (SAXException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
When you deal with resources you should use the following approach:
1) Take resource URI
URI aTestNgURI = TestRunner.class.getClassLoader().getResource("A_TestNG.xml").toURI();
2) Obtain path to a file
String aTestNgFilePath = new File(aTestNgURI).getAbsolutePath();

Extent Reports 4 - Java

Trying to generate one extent report, that will allow me to run a suite of test classes and give output as one report.
My current code below runs fin, it will run my testNG.xml file and successfully run all test classes in my suite. THe extent report itself however, only seems to save the last test cases run to it. I can't for the life of me figure out how to stop it overwriting, and append to it instead. Older version of extent report uses htmlreporter.setAppendExisting(true); but that does not exist in extent 4..
public class ExtentManager {
ExtentHtmlReporter htmlReporter;
ExtentReports extent;
ExtentTest parentTest;
ExtentTest childTest;
DriverManager driverManager;
WebDriver driver;
Screenshot screenshot;
Properties config;
String timeStamp = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss").format(new Date());
/** Suite test as it will run, with Before/After instructions*/
#BeforeTest
public void beforeTest() throws IOException {
/**Create extent reports and configure html report*/
htmlReporter = new ExtentHtmlReporter(".//reports/ExtentReport"+timeStamp+".html");
extent = new ExtentReports();
extent.attachReporter(htmlReporter);
htmlReporter.config().setTheme(Theme.DARK);
htmlReporter.config().setDocumentTitle("Automation Testing");
htmlReporter.config().setReportName("My Report");
htmlReporter.config().setAutoCreateRelativePathMedia(true);
htmlReporter.config().setTimeStampFormat("HH:mm:ss");
screenshot = new Screenshot();
config = new Properties();
FileInputStream fis = new FileInputStream(System.getProperty("user.dir") + "/src/main/resources/Config.properties");
config.load(fis);
}
public ExtentReports getExtent(){
if(extent != null){
return this.extent;
} else {
return new ExtentReports();
}
}
#BeforeClass
public void beforeClass() {
/**Setup parent test, all child tests to follow
*will attach to it for html report*/
extent = getExtent();
parentTest = extent.createTest(getClass().getSimpleName());
driverManager = new DriverManager();
driver = driverManager.getWebDriver();
driver.manage().timeouts().pageLoadTimeout(15, TimeUnit.SECONDS);
}
#AfterMethod
public void getResult(ITestResult result) throws IOException {
if (result.getStatus() == ITestResult.SUCCESS){
childTest.log(Status.PASS, MarkupHelper.createLabel("Test Case: " + result.getName() + " PASSED", ExtentColor.GREEN));
}else if(result.getStatus() == ITestResult.FAILURE){
String screenshotPath = screenshot.getScreenshot(driver, result.getName());
childTest.log(Status.FAIL, MarkupHelper.createLabel("Test Case: " + result.getName() + " FAILED", ExtentColor.RED));
childTest.fail(result.getThrowable().getMessage());
childTest.log(Status.WARNING, "Error screenshot captured and stored # " + screenshotPath);
childTest.addScreenCaptureFromPath(screenshotPath);
}else if(result.getStatus() == ITestResult.SKIP){
childTest.log(Status.SKIP, MarkupHelper.createLabel("Test Case: " + result.getName() + " SKIPPED", ExtentColor.AMBER));
childTest.log(Status.SKIP, "Skipped test: " + result.getName());
}
}
#AfterTest
public void afterTest(){
driverManager.quitWebDriver();
}
#AfterSuite
public void afterSuite() {
extent.flush();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="sanity_tests" parallel="false" verbose="10">
<test name="test1" parallel="false" preserve-order="true" verbose="10">
<classes>
<class name="com.testFramework.Tests.test1"/>
</classes>
</test>
<test name="test2" parallel="false" preserve-order="true" verbose="10">
<classes>
<class name="com.testFramework.Tests.test2"/>
</classes>
</test>
</suite>
you can use the Extent report adapters and with that there is no need to write any code, check the below article out. In your case- you will need to use the TestNG adapter-
Try this: https://www.linkedin.com/pulse/extent-framework-adapters-anshoo-arora/`

How to use screeshotcapture in IReporter interface in Selenium using TestNG?

I am using IReporter TestNG interface in Selenium, but how to capture screenshot and add in Extent Report for failed test-case ?
Please help me to find the solution.
Below is the code for attaching failed test case screenshots to the Extent Report.
MyReporterClass implements IReporter interface: It iterates over the test cases in the test suite and saves the status for each test case.
public class MyReporterClass implements IReporter {
#Override
public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
//Iterating over each suite included in the test
for (ISuite suite : suites) {
//Following code gets the suite name
String suiteName = suite.getName();
//Getting the results for the said suite
Map<String, ISuiteResult> suiteResults = suite.getResults();
for (ISuiteResult sr : suiteResults.values()) {
ITestContext tc = sr.getTestContext();
System.out.println("Passed tests for suite '" + suiteName +
"' is:" + tc.getPassedTests().getAllResults().size());
System.out.println("Failed tests for suite '" + suiteName +
"' is:" + tc.getFailedTests().getAllResults().size());
System.out.println("Skipped tests for suite '" + suiteName +
"' is:" + tc.getSkippedTests().getAllResults().size());
}
}
}
}
getScreenshot() method: To capture the screenshot and return the destination path for the screenshot.
public class ExtentReportsClass{
public static String getScreenshot(WebDriver driver, String screenshotName) throws Exception {
//below line is just to append the date format with the screenshot name to avoid duplicate names
String dateName = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date());
TakesScreenshot ts = (TakesScreenshot) driver;
File source = ts.getScreenshotAs(OutputType.FILE);
//after execution, you could see a folder "FailedTestsScreenshots" under src folder
String destination = System.getProperty("user.dir") + "/FailedTestsScreenshots/"+screenshotName+dateName+".png";
File finalDestination = new File(destination);
FileUtils.copyFile(source, finalDestination);
//Returns the captured file path
return destination;
}
}
#AfterMethod
public void getResult(ItestResult result): It is executed after each test case execution and attaches the failed test case screenshot to Extent report.
#AfterMethod
public void getResult(ITestResult result) throws IOException{
if(result.getStatus() == ITestResult.FAILURE){
logger.log(LogStatus.FAIL, "Test Case Failed is "+result.getName());
logger.log(LogStatus.FAIL, "Test Case Failed is "+result.getThrowable());
//To capture screenshot path and store the path of the screenshot in the string "screenshotPath"
String screenshotPath = ExtentReportsClass.getScreenshot(driver, result.getName());
//To add it in the extent report
logger.log(LogStatus.FAIL, logger.addScreenCapture(screenshotPath));
}else if(result.getStatus() == ITestResult.SKIP){
logger.log(LogStatus.SKIP, "Test Case Skipped is "+result.getName());
}
testng.xml file : Include the below listener tag in the xml file .
<listeners>
<listener class-name="packagename.MyReporterClass" />
</listeners>

How to log Test Suite name before suite

I want to log name of the test suite before running it. I succeed on logging method names but couldn't figure out how I can do the same thing with suites. My code:
EDIT: I found the solution. Here is the code for those who need it.
public class TestCase {
private Logger logger = LogManager.getLogger(this.getClass());
protected static WebDriver driver;
private String url = PropertyManager.getUrl();
private String browser = PropertyManager.getBrowser();
#BeforeSuite
protected void setUp(ITestContext tes) {
System.setProperty("webdriver.chrome.driver","chromedriver.exe");
System.setProperty("webdriver.chrome.logfile", "chromedriver.log");
System.setProperty("webdriver.chrome.verboseLogging", "true");
driver = new ChromeDriver();
driver.get(url);
driver.manage().window().maximize();
logger.info("Starting up {} driver.", browser);
logger.info(tes.getSuite().getName());
}
This can be done by adding Listener in the project. Use IInvokedMethodListener to perform activities before invocation of intended method.
Steps:
Create a class lets say ListenerClass and implement IInvokedMethodListener interface in it.
public class ListenerClass implements IInvokedMethodListener
Add all unimplemented method and add below code in beforeInvocation method :
#SuppressWarnings("deprecation")
#Override
public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
try {
if (method.getTestMethod().getMethod().getAnnotation(org.testng.annotations.BeforeSuite.class)
.toString() != null) {
System.out.println("Before suite annoted method name - " + method.getTestMethod().getMethodName());
System.out.println("Test suite name - " + testResult.getTestContext().getSuite().getName());
}
} catch (Exception e) {
}
}
Add the listener class in your testng.xml file
<listeners>
<listener class-name="ListenerClass"></listener>
</listeners>
<test name="Test_Name">
<classes>
<class name="Test_Class_Name" />
</classes>
</test> <!-- Test -->
Run testng.xml as TestNGSuite you will get the expected result. Let me know if any thing is there

Create Custom TestNG Report - WebDriver

I'm trying to implement org.testng IReporter Interface. My Java is not that great, base on some example I found online I was able to create a Reporter class. The problem I'm having is how to use it and where do I call it and how and which parameters to pass to it?
public class Reporter implements IReporter {
public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory){
ISuiteResult results =suites.get(0).getResults().get("Sanity Suite");
ITestContext context = results.getTestContext();
IResultMap passedTests = context.getPassedTests();
IResultMap failedTests = context.getFailedTests();
// Print all test exceptions...
for( ITestResult r: failedTests.getAllResults()) {
System.out.println( r.getThrowable());
}
}
}
For example I have this WebDriver Selenium TestNG test:
public class VerifyTest extends TestBase {
#Test
public void test1() {
verifyTrue(false);
verifyEquals("pass", "fail");
verifyFalse(true);
}
#Test
public void test2() {
verifyTrue(false);
assertEquals("pass", "fail");
verifyFalse(true);
}
How would I use my Reporter to get a customize report at the end of the run???
Thank You!
Just expand your skeleton above to generate your results where you want them, .xml, .html, text file, etc...
David, you can add your custom reporter to your testng.xml in case you are invoking your tests through an xml in the suite section.
<listeners>
<listener class-name="yourpackage.Reporter"/> </listeners>
In case you are programmatically invoking those, then you need to add it through your code as documented # Running TestNG programmatically
If you are invoking your tests from command line, refer this
This reporter would be invoked by TestNG at then end of all the runs, if you specify in either of the above ways.
I created a project that is an example of generating a customized report.
The basic idea is to create a Listener class and reference it in the testing.xml file.
<listeners>
<listener class-name="qa.hs.framework.CustomReportListener"/>
</listeners>
And then create the class:
public class CustomReportListener implements IReporter {
#Override
public void generateReport( List<XmlSuite> xmlSuites, List<ISuite> suites,
String outputDirectory ) {
System.out.println();
//Iterating over each suite included in the test
for (ISuite suite : suites) {
//Following code gets the suite name
String suiteName = suite.getName();
//Getting the results for the said suite
Map<String, ISuiteResult> suiteResults = suite.getResults();
for ( ISuiteResult sr : suiteResults.values() ) {
ITestContext tc = sr.getTestContext();
System.out.println("Passed tests for suite '" + suiteName + "' is:" +
tc.getPassedTests().getAllResults().size());
}
CustomReport cr = new CustomReport();
cr.generateReport( xmlSuites, suites, outputDirectory );
...
Then, from that Listener class you can create a "Report Writer" class that creates any arbitrary HTML output using something like so:
public class CustomReport extends CustomReportListener
{
private static final Logger LOG = Logger.getLogger( CustomReport.class );
private static final SimpleDateFormat dateFormatter = new SimpleDateFormat(" MMM d 'at' hh:mm a");
private String reportFileName = Constants.reportFileName;
private PrintWriter m_out;
private int m_row;
private Integer m_testIndex;
private int m_methodIndex;
private Scanner scanner;
#Override
public void generateReport( List<XmlSuite> xml, List<ISuite> suites, String outdir ) {
try {
m_out = createWriter( outdir );
}
catch ( IOException e ) {
LOG.error("output file", e);
return;
}
startHtml(m_out);
generateSuiteSummaryReport(suites);
generateMethodSummaryReport(suites);
generateMethodDetailReport(suites);
endHtml(m_out);
m_out.flush();
m_out.close();
}
And finally, from that "CustomReport" class your "generate report" methods all have access to all data from the report, such as:
testContext.getPassedTests()
Map<String, ISuiteResult> r = suite.getResults()
method.getDescription()
method.getTestClass().getName()
ITestResult.SUCCESS
tests.getAllMethods()
overview.getStartDate().getTime()
overview.getIncludedGroups()
etc.
You can use
#Listeners(ReporterClassName.class)
ex:
#Listeners(Reporter.class)
public class VerifyTest extends TestBase
Beautiful reporting with realtime report of any running test is possible using RealTime report plugin. Very easy to use and no modification needed in existing code, for details please visit this github url RealTimeReport
You can find details implementation of different TestNg Reporting intrfaces

Categories

Resources