Getting Started
ExtentReports is an logger-style reporting library for automated tests. A logger is simply an object to log messages or events for a specific system or application. ExtentReports uses the logging style to add information about test sessions, such as creation of tests, adding screenshots, assigning tags, and adding events or series of steps to sequentially indicate the flow of test steps.
Migrating from previous versions
This document assume you are upgrading from ExtentReports 4.0 or later. The upgrade path from versions 3.0 and earlier requires taking into account many additional changes to the underlying API. Such changes are not described here and in this situation, the recommended approach is to refer to this guide for usage instructions.
Breaking Changes
If you are upgrading from version 4, the upgrade path is quite straight-forward. This document details all the breaking changes on a version 4.0 to 5.0 upgrade path. If you encounter any change other than the ones listed here, please file an issue here.
ExtentHtmlReporter, ExtentLoggerReporter
The ExtentHtmlReporter and ExtentLoggerReporter were deprecated in series 4.1.x and have been removed in version 5. The replacement is ExtentSparkReporter, which is comprehensive, ports all features along with a host of new ones.
ExtentReports::getStartedReporters
ExtentReports::getStartedReporters
has been removed. It is no longer possible to obtain a list of started reporters via the API.ExtentReports::detachReporter
ExtentReports::detachReporter
has been removed. It is no longer possible to detach observers once they have been subscribed.ExtentReports:setTestRunnerOutput
ExtentReports:setTestRunnerOutput
renamed toaddTestRunnerOutput
. This change was made to add clarity to what this method did behind the scenes, which is adding output from test runners instead of setting it only once.Changes to the Status enumeration
Status::ERROR
,Status::FATAL
,Status::DEBUG
have been removed to be inline with the major Java test-frameworks (JUnit and TestNG). The following are the current options:- Info
- Pass
- Warning
- Skip
- Fail
Reporter::enableTimeline
Reporter::enableTimeline renamed to Reporter::setTimelineEnabled.
Installation: Community
ExtentReports can be used with classic Java setup, just like any standard Java library. Although you can copy the ExtentReports jars, the recommended way is to use dependency management tools such as Maven or Gradle (below). The only requirement is you need Java SDK v1.8 or higher. Before you begin, you should check the version of installed JDK using the following command:
$ java -version
Note: The package com.relevantcodes was used upto version 2. com.aventstack is the package for Versions 3+.
Maven
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>${version}</version>
</dependency>
Gradle
dependencies {
compile "com.aventstack:extentreports:${version}"
}
GitHub
Installation: Professional
Once you have completed the steps above in Installation: Community, follow the instructions included as outlined in ExtentReportsSetup.pdf
available over your FTP.
Maven
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports-pro</artifactId>
<version>${version}</version>
</dependency>
Gradle
dependencies {
compile "com.aventstack:extentreports:${version}",
compile "com.aventstack:extentreports-pro:${version}"
}
Reporters
Extent allows creation of tests, nodes, events and assignment of tags, devices, authors, environment values etc. This information can be printed to multiple destinations. In our context, a reporter defines the destination.
You can use one or more reporters to create different types of reports. reporters are available for BDD, non-BDD and both - choose one of the reporters from the navigation menu at the top of this page to learn more.
- ExtentSparkReporter
ExtentSparkReporter spark = new ExtentSparkReporter("Spark.html");
ExtentAventReporterExtentAventReporter avent = new ExtentAventReporter("Avent.html");
- ExtentEmailReporter (available in a future release)
ExtentEmailReporter email = new ExtentEmailReporter("Email.html");
- ExtentKlovReporter
ExtentKlovReporter klov = new ExtentKlovReporter("ProjectName") .initWithDefaultSettings();
Usage
ExtentReports is an logger-style reporting library for automated tests. A logger is simply an object to log messages or events for a specific system or application. ExtentReports uses the logging style to add information about test sessions, such as creation of tests, adding screenshots, assigning tags, and adding events or series of steps to sequentially indicate the flow of test steps.
All methods on ExtentReports are multi-thread safe. The recommended usage is to maintain a single instance of ExtentReports object for your test session.
ExtentReports extent = new ExtentReports();
For brevity, wherever extent
is mentioned, it would indicate an instance of ExtentReports
.
Below is how a test would be created with 1 passing log.
extent.createTest("MyFirstTest")
.log(Status.Pass, "This is a logging event for MyFirstTest, and it passed!");
extent.flush();
The line extent.flush()
instructs ExtentReports write the test information to a destination. However, the examples above are incomplete as we need to define a destination where they will be saved. Reporters (next section) define the destination.
Reporters
The information you create during your runs can be forwarded to a variety of destinations including files, database or stored in memory to be used at a later point in time.
ExtentReports uses the Observer pattern
making all reporters observers that are known by ExtentReports.
Below, an instance of ExtentSparkReporter
(the Observer) is attached to ExtentReports (the Subject), which notifies ExtentSparkReporter of any changes in state such as creation of tests, adding logs etc.
ExtentReports extent = new ExtentReports();
ExtentSparkReporter spark = new ExtentSparkReporter("target/Spark.html");
extent.attachReporter(spark);
extent.createTest("MyFirstTest")
.log(Status.PASS, "This is a logging event for MyFirstTest, and it passed!");
extent.flush();
Running the above code would produce the file Spark.html in the target folder of your project root.
Multiple Reporters
You can attach multiple reporters and output the same information to each:
ExtentReports extent = new ExtentReports();
ExtentSparkReporter spark = new ExtentSparkReporter("target/Spark.html");
ExtentKlovReporter klov = new ExtentKlovReporter("MyProject")
.initWithDefaultSettings();
extent.attachReporter(spark, klov);
extent.createTest("MyFirstTest")
.log(Status.PASS, "This is a logging event for MyFirstTest, and it passed!");
extent.flush();
ExtentReports extent = new ExtentReports();
ExtentSparkReporter spark = new ExtentSparkReporter("target/spark.html");
ExtentEmailReporter email = new ExtentEmailReporter("target/email.html");
extent.attachReporter(spark, email);
Filters
It is possible to create separate reports for each status (or a group of them). For example, 2 reports can be created per run session to:
- view all tests
- view only failed ones
The example below shows ExtentReports
attaching 2 instances of ExtentSparkReporter
: one adding all tests and the other only failed.
// will only contain failures
ExtentSparkReporter sparkFail = new ExtentSparkReporter("target/SparkFail.html")
.filter()
.statusFilter()
.as(new Status[] { Status.FAIL })
.apply();
// will contain all tests
ExtentSparkReporter sparkAll = new ExtentSparkReporter("spark/SparkAll.html");
extent.attachReporter(sparkFail, sparkAll);
View Order
It is also possible to select the views and their order. The example below will limit the views to only 2: Dashboard and Test. It will also make Dashboard as the primary view of the report.
Only Avent and Spark reporters support this configuration.
ExtentSparkReporter spark = new ExtentSparkReporter("spark/spark.html")
.viewConfigurer()
.viewOrder()
.as(new ViewName[] { ViewName.DASHBOARD, ViewName.TEST })
.apply();
The default setting is to display all views in this order:
- Test (default: primary)
- Category
- Device
- Author
- Exception
- Dashboard
- Log
If you intend to change the view order to a view other than Test as the primary, while maintaining presence of all others, use:
ExtentSparkReporter spark = new ExtentSparkReporter("spark/spark.html")
.viewConfigurer()
.viewOrder()
.as(new ViewName[] {
ViewName.DASHBOARD,
ViewName.TEST,
ViewName.TAG,
ViewName.AUTHOR,
ViewName.DEVICE,
ViewName.EXCEPTION,
ViewName.LOG
})
.apply();
Create Tests
Tests are created using ExtentReports::createTest
. The createTest
method returns a ExtentTest
object which can be used to publish logs, create nodes, assign attributes (tags, devices, authors) or attach screenshots.
ExtentTest test = extent.createTest("MyFirstTest");
test.pass("Pass");
// fluent
ExtentTest test = extent.createTest("MyFirstTest").pass("Pass");
Nodes
ExtentReports creates the test and returns an ExtentTest
object, which can create nodes using createNode
. Depending on the output and reporter type, this method creates a subsection within the test, generally as a box or toggle.
ExtentTest test = extent.createTest("MyFirstTest");
ExtentTest node = test.createNode("Node");
node.pass("Pass");
// fluent
ExtentTest node = extent.createTest("MyFirstTest")
.createNode("Node")
.pass("Pass");
BDD
ExtentReports support Gherkin-style reports using the same nested structure as shown in the previous section using createNode
. The BDD hierarchy can be created using Gherkin classes provided by the ExtentReports library:
ExtentTest feature = extent.createTest(Feature.class, "Refund item");
ExtentTest scenario = feature.createNode(Scenario.class, "Jeff returns a faulty microwave");
scenario.createNode(Given.class, "Jeff has bought a microwave for $100").pass("pass");
scenario.createNode(And.class, "he has a receipt").pass("pass");
scenario.createNode(When.class, "he returns the microwave").pass("pass");
scenario.createNode(Then.class, "Jeff should be refunded $100").fail("fail");
The above can also be written without specifying the BDD class by passing the keyword:
ExtentTest feature = extent.createTest(new GherkinKeyword("Feature"), "Refund item");
ExtentTest scenario = feature.createNode(new GherkinKeyword("Scenario"), "Jeff returns a faulty microwave");
scenario.createNode(new GherkinKeyword("Given"), "Jeff has bought a microwave for $100").pass("pass");
scenario.createNode(new GherkinKeyword("And"), "he has a receipt").pass("pass");
scenario.createNode(new GherkinKeyword("When"), "he returns the microwave").pass("pass");
scenario.createNode(new GherkinKeyword("Then"), "Jeff should be refunded $100").fail("fail");
Gherkin Dialect
To specify the dialect of your Gherkin keywords, use setGherkinDialect
. This method is helpful if you are using Gherkin keywords not supported out-of-box by ExtentReports, but are supported with Gherkin.
extent.setGherkinDialect("de");
ExtentTest feature = extent.createTest(new GherkinKeyword("Funktionalität"), "Refund item VM");
ExtentTest scenario = feature.createNode(new GherkinKeyword("Szenario"), "Jeff returns a faulty microwave");
ExtentTest given = scenario.createNode(new GherkinKeyword("Angenommen"), "Jeff has bought a microwave for $100").skip("skip");
Remove Tests
Using removeTest
completely deletes the test from the run session. Note: this method will also remove all information associated with the test, including logs, screenshots, children (nodes), tags etc.
ExtentTest test = extent.createTest("Test").fail("reason");
extent.removeTest(test);
// or remove using test name
extent.removeTest("Test");
Removing Nodes
ExtentTest test = extent.createTest("Test");
ExtentTest node = test.createNode("Node").fail("reason");
extent.removeTest(node);
// or remove using test name
extent.removeTest("node");
Logging
It is possible to create log with text details, Exception/Throwable, ScreenCapture or custom Markup using MarkupHelper.
Details
ExtentTest test = extent.createTest("MyFirstTest");
test.pass("Text details");
test.log(Status.PASS, "Text details");
Exceptions
Throwable t = new RuntimeException("A runtime exception");
ExtentTest test = extent.createTest("MyFirstTest");
test.fail(t);
test.log(Status.FAIL, t);
Screenshots
ExtentTest test = extent.createTest("MyFirstTest");
// reference image saved to disk
test.fail(MediaEntityBuilder.createScreenCaptureFromPath("img.png").build());
// base64
test.fail(MediaEntityBuilder.createScreenCaptureFromBase64String("base64").build());
Markup
More information on this topic can be found in the Markup System section.
String json = "{'foo' : 'bar', 'foos' : ['b','a','r'], 'bar' : {'foo':'bar', 'bar':false,'foobar':1234}}";
test.info(MarkupHelper.createCodeBlock(json, CodeLanguage.JSON));
Attributes/Tagging
Assign Tags
You can assign tags or categories to tests using assignCategory
.
test.assignCategory("tag");
test.assignCategory("tag-1", "tag-2", ..);
// usage
extent.createTest("Test").assignCategory("tag-1").pass("details");
Assigning tags enables the Tag view in BasicFileReporter
reporters.
Assign Devices
You can assign devices to tests using assignDevice
.
test.assignDevice("device-name");
test.assignDevice("device-1", "device-2", ..);
// usage
extent.createTest("Test").assignDevice("device-name").pass("details");
Assign Authors
You can assign categories to tests using assignAuthor
.
test.assignAuthor("author");
test.assignAuthor("author-1", "author-2", ..);
// usage
extent.createTest("MyFirstTest").assignAuthor("aventstack").pass("details");
System Info
It is possible to add system or environment info for your using using the setSystemInfo
method. This automatically adds system information to all started reporters.
extent.setSystemInfo("os", "macos");
Custom Logs
You can create your own custom logs, tables with custom headers, pass your objects directly to be converted into a table etc. You can also specify any CSS classes to be applied on the table, like in the below example with "table-sm" (a bootstrap table class).
public class MyCustomLog {
private List<Object> names = Arrays.asList("Anshoo", "Extent", "Klov");
private Object[] favStack = new Object[]{"Java", "C#", "Angular"};
@MarkupIgnore
private List<Object> ignored = Arrays.asList("Ignored", "Ignored", "Ignored");
private Map<Object, Object> items = new HashMap<Object, Object>() {
{
put("Item1", "Value1");
put("Item2", "Value2");
put("Item3", "Value3");
}
};
}
extent.createTest("GeneratedLog")
.generateLog(Status.PASS, MarkupHelper.toTable(new MyCustomLog(), "table-sm"));
Combine Multiple Reports
Starting version 5, a JsonFormatter
is available, which uses a JSON representation of the run session to create the internal entities and combine results from multiple build sessions into one. The method createDomainFromJsonArchive
is responsible for using the JSON extract to recreate entities.
ExtentSparkReporter spark = new ExtentSparkReporter("spark.html");
JsonFormatter json = new JsonFormatter("extent.json");
ExtentReports extent = new ExtentReports();
extent.createDomainFromJsonArchive("extent.json");
extent.attachReporter(json, spark);
In the above example, a JsonFormatter
is created which saves the complete entity information as a JSON file to ./extent.json
. The 1st time createDomainFromJsonArchive
is called, no actions are performed because the file is empty. 2nd time onwards, whenever this method is called, it will read the entities and rebuild them.
The method createDomainFromJsonArchive
must be called before extent.attachReporter()
.
Markup System
Version 5 improves upon the markup system introduced in version 4. Table and Codeblocks are vastly enhanced and List is a newly added element starting 5.0.0
.
Table
Tables can be created from String[][] or a custom object (as shown below).
public class MyCustomLog {
private List<Object> names = Arrays.asList("Anshoo", "Extent", "Klov");
private Object[] favStack = new Object[]{"Java", "C#", "Angular"};
@MarkupIgnore
private List<Object> ignored = Arrays.asList("Anshoo/Ignore", "Extent/Ignore", "Klov/Ignore");
private Map<Object, Object> items = new HashMap<Object, Object>() {
{
put("Item1", "Value1");
put("Item2", "Value2");
put("Item3", "Value3");
}
};
}
// create table as a custom log
extent.createTest("GeneratedLog")
.generateLog(Status.FAIL, MarkupHelper.toTable(new MyCustomLog(), "table-sm"));
// or as a predefined one:
extent.createTest("Log")
.fail(MarkupHelper.toTable(new MyCustomLog(), "table-sm"));
CodeBlock
CodeBlocks are helpful if you intend to display pre-formatted code.
XML
String code = "<root>" +
"\n <Person>" +
"\n <Name>Joe Doe</Name>" +
"\n <StartDate>2007-01-01</StartDate>" +
"\n <EndDate>2009-01-01</EndDate>" +
"\n <Location>London</Location>" +
"\n </Person>" +
"\n</root>";
Markup m = MarkupHelper.createCodeBlock(code);
test.info(m);
JSON
String json = "{'foo' : 'bar', 'foos' : ['b','a','r'], 'bar' : {'foo':'bar', 'bar':false,'foobar':1234}}";
test.pass(MarkupHelper.createCodeBlock(json, CodeLanguage.JSON));
Multiple CodeBlocks
It is possible to include upto 4 code-blocks horizontally. Considering an example of a REST API test where you have a request/response, they can both be logged in a single line.
String code = "<root>" +
"\n <Person>" +
"\n <Name>Joe Doe</Name>" +
"\n <StartDate>2007-01-01</StartDate>" +
"\n <EndDate>2009-01-01</EndDate>" +
"\n <Location>London</Location>" +
"\n </Person>" +
"\n</root>";
Markup m = MarkupHelper.createCodeBlock(code, code);
// or:
Markup m = MarkupHelper.createCodeBlocks(new String[] { code, code });
List
Use MarkupHelper::createOrderedList or MarkupHelper::createUnorderedList to display information as ordered or unordered list.
Ordered
List<Object> items = Arrays.asList(new Object[] { "Item1", "Item2", "Item3" });
extent.createTest("Test").info(MarkupHelper.createOrderedList(items));
Unordered
Map<Object, Object> items = new HashMap<Object, Object>()
{{
put("Item1", "Value1");
put("Item2", "Value2");
put("Item3", "Value3");
}};
extent.createTest("Test").info(MarkupHelper.createUnorderedList(items).getMarkup());
Label
A small labeling component.
test.info(MarkupHelper.createLabel("Extent", ExtentColor.BLUE));
A Complete Example
This document shows a complete example of some of the different approaches you can use to present information.
The example is also available online here.
import com.aventstack.extentreports.markuputils.MarkupHelper;
import com.aventstack.extentreports.reporter.ExtentSparkReporter;
public class Main {
private static final String CODE1 = "{\n \"theme\": \"standard\",\n \"encoding\": \"utf-8\n}";
private static final String CODE2 = "{\n \"protocol\": \"HTTPS\",\n \"timelineEnabled\": false\n}";
public static void main(String[] args) throws ClassNotFoundException {
ExtentReports extent = new ExtentReports();
ExtentSparkReporter spark = new ExtentSparkReporter("target/Spark/Spark.html");
extent.attachReporter(spark);
extent.createTest("ScreenCapture")
.addScreenCaptureFromPath("extent.png")
.pass(MediaEntityBuilder.createScreenCaptureFromPath("extent.png").build());
extent.createTest("LogLevels")
.info("info")
.pass("pass")
.warning("warn")
.skip("skip")
.fail("fail");
extent.createTest("CodeBlock").generateLog(
Status.PASS,
MarkupHelper.createCodeBlock(CODE1, CODE2));
extent.createTest("ParentWithChild")
.createNode("Child")
.pass("This test is created as a toggle as part of a child test of 'ParentWithChild'");
extent.createTest("Tags")
.assignCategory("MyTag")
.pass("The test 'Tags' was assigned by the tag <span class='badge badge-primary'>MyTag</span>");
extent.createTest("Authors")
.assignAuthor("TheAuthor")
.pass("This test 'Authors' was assigned by a special kind of author tag.");
extent.createTest("Devices")
.assignDevice("TheDevice")
.pass("This test 'Devices' was assigned by a special kind of devices tag.");
extent.createTest("Exception! <i class='fa fa-frown-o'></i>")
.fail(new RuntimeException("A runtime exception occurred!"));
extent.flush();
}
}