I am using spring-boot cucumber with TestNG to write and API test framework ,
wanted to undersatand how can add tags and feature file to executed based on environment selected
Below is my current implementation
@CucumberOptions(
features = {"src/test/resources/Features"},
glue = {"als.system.tests.stepDefinations"},
plugin = {"pretty", "html:target/cucumber-html-report.html"}
)
public class CucumberRunnerTests extends AbstractTestNGCucumberTests {
}
And skipping test based on tags , but this is not ideal solution and also dont want to display skipped test on report
@Before
public void setup(Scenario scenario) {
if (!scenario.getSourceTagNames().contains("@" + productName.toLowerCase())) {
throw new SkipException("Skipping /Ignoring this scenario as not part of executions !!!");
}
}
Is there clean way to achieve this ?
Here's how you do it.
7.6.1
as of today and it needs JDK11)com.rationaleemotions.TagBasedInterceptor
<listener>
tag (or) using the service provider interface approach. For details on this, you can refer to the official TestNG documentation here (or) refer to my blog-post here.Below is a sample implementation of the listener
import io.cucumber.testng.PickleWrapper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import org.testng.IDataProviderInterceptor;
import org.testng.IDataProviderMethod;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
public class TagBasedInterceptor implements IDataProviderInterceptor {
@Override
public Iterator<Object[]> intercept(Iterator<Object[]> original,
IDataProviderMethod dataProviderMethod, ITestNGMethod method, ITestContext iTestContext) {
String rawTag = iTestContext.getCurrentXmlTest().getParameter("tag");
if (rawTag == null || rawTag.trim().isEmpty()) {
return original;
}
List<String> tags = Arrays.asList(rawTag.trim().split(","));
List<Object[]> pruned = new ArrayList<>();
while (original.hasNext()) {
Object[] currentElement = original.next();
Optional<Object> searchResult = findPickleWrapper(currentElement);
if (searchResult.isEmpty()) {
continue;
}
PickleWrapper pickleWrapper = searchResult.map(element -> (PickleWrapper) element).get();
boolean tagPresent = pickleWrapper.getPickle().getTags()
.stream().anyMatch(tags::contains);
if (tagPresent) {
pruned.add(currentElement);
}
}
return pruned.iterator();
}
private Optional<Object> findPickleWrapper(Object[] each) {
return Arrays.stream(each)
.filter(element -> element instanceof PickleWrapper)
.findFirst();
}
}
Here's how the suite xml would look like
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Default Suite" verbose="2">
<listeners>
<listener class-name="com.rationaleemotions.TagBasedInterceptor"/>
</listeners>
<parameter name="tag" value="dragon_warrior"/>
<test name="testng_playground">
<classes>
<class name="com.rationaleemotions.CucumberRunnerTests">
</class>
</classes>
</test>
</suite>
Below are the dependencies that I am using for this sample
<dependencies>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-testng -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>7.8.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-java -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>7.8.0</version>
</dependency>
</dependencies>
Feel free to enhance the listener such that if it also reads from the JVM argument (which you can specify using -D
) so that you can have the dynamic behaviour of overriding the tag value in the suite xml with something that can be specified as a tag (or a comma separated list of tags) through the JVM argument.