Skip to content

Usage Guide

Anshoo Arora edited this page Aug 14, 2020 · 5 revisions

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.

ExtentSparkReporter output

Report filters for Status/Tag specific reports

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:

  1. view all tests
  2. 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.

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:

  1. Test (default: primary)
  2. Category
  3. Device
  4. Author
  5. Exception
  6. Dashboard
  7. 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");

Nodes

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");

Nested BDD Steps

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);

ScreenCapture

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));

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"));