-
Notifications
You must be signed in to change notification settings - Fork 30
Nested steps
Nested steps are implemented in a way to be suitable for any Report Portal java agent. But they use AspectJ to catch @Step
annotation
during the test runtime. AspectJ requires to be configured. Here are the most common ways to do this.
If you run your tests in plain java command-line you need to download AspectJ Weaver jar file somewhere to your machine and specify
-javaagent:/path/to/aspectjweaver-1.9.8.jar
JVM arg. Along with that you should keep Report Portal Agent dependencies somewhere in your
classpath.
E.G.:
java -javaagent:/path/to/aspectjweaver-1.9.8.jar -jar testng-tests-1.0.0-SNAPSHOT.jar /path/to/SuteXmlFile.xml
In gradle it's pretty simple to add AspectJ support to your test. You just need to specify the dependency and add some initialization logic into your test task.
dependencies {
testImplementation 'com.epam.reportportal:agent-java-junit5:5.1.1'
testImplementation 'org.aspectj:aspectjweaver:1.9.2'
}
test {
doFirst {
def weaver = configurations.testRuntimeClasspath.find { it.name.contains("aspectjweaver") }
jvmArgs += "-javaagent:$weaver"
}
}
In maven required configuration a little lengthy, since you need to specify dependencies and a test plugin:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.epam.reportportal.example</groupId>
<artifactId>example-steps</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.epam.reportportal</groupId>
<artifactId>agent-java-junit5</artifactId>
<version>5.1.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<!-- Required for nested steps -->
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
</argLine>
</configuration>
<dependencies>
<!-- Required for nested steps -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
Nested steps is a common way to group your test logs into small described pieces. Here is how one of our internal test looks like:
Let's imagine we have a test for some products ordering flow:
public class Test {
@Test
void orderProductsTest() {
final Integer productCount = 5;
final Double price = 3.0;
final Double totalPrice = price * productCount;
LOGGER.info("Main page displayed");
OrderingSimulator.logIn();
LOGGER.info("User logged in");
List<String> products = OrderingSimulator.getProducts();
LOGGER.info("Products page opened");
String product = OrderingSimulator.chooseProduct();
LOGGER.info("Product click event");
LOGGER.info(productCount + " products selected");
OrderingSimulator.addProduct(product, productCount);
LOGGER.info(productCount + " products added to the cart");
Assert.assertEquals(5, productCount);
OrderingSimulator.doPayment(totalPrice);
LOGGER.info("Successful payment");
OrderingSimulator.logOut();
LOGGER.info("User logged out");
}
}
After running this method with our listener we have next results on the Report Portal page:
Pretty much stuff with different logic is included in the one single test method. So we can move different operations to separate methods:
public class Test {
@Test
void orderProductsTest() {
final Integer productCount = 5;
final Double price = 3.0;
final Double totalPrice = price * productCount;
navigateToMainPage();
login();
navigateToProductsPage();
addProductToCart(productCount);
pay(totalPrice);
logout();
}
public void navigateToMainPage() {
LOGGER.info("Main page displayed");
}
public void login() {
OrderingSimulator.logIn();
LOGGER.info("User logged in");
}
public void navigateToProductsPage() {
List<String> products = OrderingSimulator.getProducts();
LOGGER.info("Products page opened");
}
public void addProductToCart(Integer count) {
String product = clickOnProduct();
selectProductsCount(count);
clickCartButton(product, count);
}
private String clickOnProduct() {
LOGGER.info("Product click event");
return OrderingSimulator.chooseProduct();
}
private void selectProductsCount(Integer count) {
LOGGER.info(count + " products selected");
}
private void clickCartButton(String product, Integer productCount) {
OrderingSimulator.addProduct(product, productCount);
LOGGER.info(productCount + " products added to the cart");
Assert.assertEquals(5, productCount);
}
public void pay(Double totalPrice) {
OrderingSimulator.doPayment(totalPrice);
LOGGER.info("Successful payment");
}
public void logout() {
OrderingSimulator.logOut();
LOGGER.info("User logged out");
}
}
Much better, but result on the Report Portal looks the same. So we grouped our logic by methods, but we cannot see our grouping on the view. That's a problem. And we can solve it using @Step annotation.
In Report Portal Step
is a TestItem
without statistics that required for splitting large test methods on multiple parts to provide clear
and concise view for them. Steps
have flexible structure and can be put under other Steps
. @Step
annotation consists of 4 fields:
public @interface Step {
String value() default "";
String description() default "";
boolean isIgnored() default false;
StepTemplateConfig templateConfig() default @StepTemplateConfig;
}
Field value
of type String
is required for TestItem
name creation using static part, templates provided by user and method arguments:
public class Test {
//static part - "My name is "
//user template - "{number}"
//parameter with name 'number' and for example value = 3
//result: "My number is 3"
@Step("My number is {number}")
public void randomMethod(String number) {
// your step logic here
}
}
Field description
of type String
contains TestItem
description value.
Field isIgnored
of type boolean
allows to enable/disable Step
handling for the current method.
Field templateConfig
contains @StepTemplateConfig annotation and required for resulted value template configuration.
You can check out Step template and step template config guide to understand template building patterns.
So now we can update our test with @Step
annotation and get a view that matches with our grouping:
public class Test {
@Test
void orderProductsTest() {
final Integer productCount = 5;
final Double price = 3.0;
final Double totalPrice = price * productCount;
navigateToMainPage();
login();
navigateToProductsPage();
addProductToCart(productCount);
pay(totalPrice);
logout();
}
@Step
public void navigateToMainPage() {
LOGGER.info("Main page displayed");
}
@Step
public void login() {
OrderingSimulator.logIn();
LOGGER.info("User logged in");
}
@Step
public void navigateToProductsPage() {
List<String> products = OrderingSimulator.getProducts();
LOGGER.info("Products page opened");
}
@Step("Add {count} products to the cart")
public void addProductToCart(Integer count) {
String product = clickOnProduct();
selectProductsCount(count);
clickCartButton(product, count);
}
@Step
private String clickOnProduct() {
LOGGER.info("Product click event");
return OrderingSimulator.chooseProduct();
}
@Step("{method} with {count} products")
private void selectProductsCount(Integer count) {
LOGGER.info(count + " products selected");
}
@Step("{productCount} products added")
private void clickCartButton(String product, Integer productCount) {
OrderingSimulator.addProduct(product, productCount);
LOGGER.info(productCount + " products added to the cart");
Assert.assertEquals(5, productCount.intValue());
}
@Step("Payment step with price = {totalPrice}")
public void pay(Double totalPrice) {
OrderingSimulator.doPayment(totalPrice);
LOGGER.info("Successful payment");
}
@Step
public void logout() {
OrderingSimulator.logOut();
LOGGER.info("User logged out");
}
}
Results on the Report Portal page:
Now we have a view where we can show/hide required steps by clicking on them.
- Callback reporting
- Nested steps
- Test item attributes
- Test case ID
- Multi-poccess execution