I understand that @CucumberOptions
is used to pass Cucumber options. However, due to the limitation that Java annotations only allow inline constants, it is quite cumbersome to use @CucumberOptions
. So, is there a dynamic way to pass Cucumber options when using cucumber-junit? Thank you very much.

- 8,498
- 18
- 65
- 104
-
What exactly would you like to pass. Could you throw in an example? – Bala Apr 01 '14 at 08:33
-
For example, if I want to pass tags dynamically, how can I do that? The advantage of passing tags is that you can filter features/scenarios you want to run dynamically. – JBT Apr 02 '14 at 17:23
6 Answers
This question is quite old now, but the answer is yes you can.
If you are using maven for example just add it like this.
mvn test -Dcucumber.options="--tags @your_tag"
You can filter yous scenarios that way when running them.
Hope this helps.

- 2,236
- 2
- 19
- 27
As mentioned here, Instead of depending on TestNG and jUnit, try to use common generic code and try to create best advantages as per your requirement. Add more options as you required.
private void defaultRun() {
List<String> arguments = new ArrayList<String>();
rguments.add("featureFiles");
String[] tags = tagsToExecute;
for (String tag : tags) {
arguments.add("--tags");
arguments.add(tag);
}
arguments.add("--plugin");
arguments.add(html);
arguments.add("--plugin");
arguments.add(json);
arguments.add("--plugin");
arguments.add(rerun);
String[] gluepackages = gluePackage.split(",");
for (String packages : gluepackages) {
if (!packages.contains("none")) {
arguments.add("--glue");
arguments.add(packages);
}
}
final String[] argv = arguments.toArray(new String[0]);
try {
executetests(argv);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public byte executetests(final String[] argv) throws InterruptedException, IOException {
RuntimeOptions runtimeOptions = new RuntimeOptions(new ArrayList(Arrays.asList(argv)));
MultiLoader resourceLoader = new MultiLoader(this.getClass().getClassLoader());
ResourceLoaderClassFinder classFinder = new ResourceLoaderClassFinder(resourceLoader, this.getClass().getClassLoader());
Runtime runtime = new Runtime(resourceLoader, classFinder, this.getClass().getClassLoader(), runtimeOptions);
runtime.run();
System.out.println(runtime.exitStatus());
return runtime.exitStatus();
}

- 1
- 1

- 478
- 4
- 16
-
This looks like an ideal solution, but where are you getting your Runtime from? The one in java.lang doesn't permit any constructors except new Runtime(), so my IDE can't find it. Plus all the functions you call on it (run, exitStatus) don't exist. – Tihamer Jul 28 '20 at 22:25
-
OK, so you are using the cucumber.runtime.Runtime version of Runtime. There were a many other things I had to fix. Comments doesn't have room: I will need to post the full solution as a separate answer. – Tihamer Jul 29 '20 at 03:22
Expanding on answer from @Pedro Lopez - Cucumber will pick up properties such as cucumber.features
and cucumber.filter.tags
from a few different places:
Cucumber will in order of precedence parse properties from system properties, environment variables, @CucumberOptions and the cucumber.properties file. Note that the CLI arguments take precedence over all.
Set these properties however you like and it should find them. For example, if you happen to be using TestNG as your runner:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Example Suite">
<parameter name="cucumber.filter.tags" value="@Gherkin and not @Zucchini" />
<test name="Vegetable garden" preserve-order="true">
<parameter name="cucumber.features" value="classpath:com/example/features/vegetable"/>
<parameter name="cucumber.glue" value="com.example.vegetables.glue"/>
<classes>
<class name="com.example.RunCucumberTests"/>
</classes>
</test>
<test name="Herb garden" preserve-order="true">
<parameter name="cucumber.features" value="classpath:com/example/features/herbs"/>
<parameter name="cucumber.glue" value="com.example.herbs.glue"/>
<classes>
<class name="com.example.RunCucumberTests"/>
</classes>
</test>
</suite>

- 1,171
- 8
- 21
You can have multiple Junit Before and After methods, each one executed by a particular tag you want(@mytag). Within each method you can set up the conditions you want.

- 581
- 4
- 11
- 27
Here is a solution inspired by Sugat Mankar's beautiful clue, but with complete code, and with the mistakes fixed (though for it to work for you, you would have to have the same package structure and location for Gherkin feature files as I do):
package mypack.cukes;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import cucumber.runtime.RuntimeOptions;
import cucumber.runtime.io.MultiLoader;
import cucumber.runtime.io.ResourceLoaderClassFinder;
import cucumber.runtime.Runtime;
public class MyRunnerTest {
public String[] tagsToExecute = {"@SmokeUtilizationData, @SmokeSummaryData, @SmokeCompliance"};
public String html = "com.cucumber.listener.ExtentCucumberFormatter:target/cucumber-reports/report.html";
public String gluePackage = "mypack.cukes.stepDefinitions";
public String[] argv = null;
public void defaultRun() {
List<String> arguments = new ArrayList<String>();
arguments.add("src/main/java/mypack/cukes/features");
String[] tags = tagsToExecute;
for (String tag : tags) {
arguments.add("--tags");
arguments.add(tag);
}
arguments.add("--plugin");
arguments.add(html);
arguments.add("--glue");
arguments.add(gluePackage);
argv = arguments.toArray(new String[arguments.size()]);
try {
executeTests(argv);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException ioex) {
ioex.printStackTrace();
}
}
public byte executeTests(final String[] argv) throws InterruptedException, IOException {
RuntimeOptions runtimeOptions = new RuntimeOptions(new ArrayList(Arrays.asList(argv)));
MultiLoader resourceLoader = new MultiLoader(this.getClass().getClassLoader());
ResourceLoaderClassFinder classFinder = new ResourceLoaderClassFinder(resourceLoader, this.getClass().getClassLoader());
Runtime runtime = new Runtime(resourceLoader, classFinder, this.getClass().getClassLoader(), runtimeOptions);
runtime.run();
System.out.println(runtime.exitStatus());
return runtime.exitStatus();
}
public static void main(String[] args) {
System.out.println("Testing MyRunnerTest");
MyRunnerTest myRun = new MyRunnerTest();
myRun.defaultRun();
}
}
BTW, my pom file says: <cucumber.version>1.2.4</cucumber.version>

- 935
- 10
- 8
-
Your solution works when I execute the main method from IntelliJ. The test is part of maven project so i want to use command line to execute such mvn clean test. But the cucumber test is skipped. – user3922604 Jan 07 '21 at 12:48
I worked with the version Tihamer posted. But that only works when executed as normal Java program. When I ran with TestNG, it doesn't work as there's no @Test available. I think that's what the comment says it doesn't work with maven commands. I work with the cucumber v7.13.0. So, after whole day of digging around the cucumber classes everywhere I found the perfect solution.
import io.cucumber.tagexpressions.TagExpressionParser;
import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;
import io.cucumber.testng.PickleWrapper;
import org.testng.annotations.DataProvider;
import java.util.ArrayList;
import java.util.List;
/**
* This runner is a hybrid runner which can run normally as local runner with Cucumber Options or run with tags variable passed from Pipeline tools or from any other sources
* <br></br>
* <br></br>
* When the tags are provided from Cucumber Options locally it needs to be in Cucumber tags format with 'and', 'or', 'not'.
* <br></br>
* But the pipeline tag variable can be passed as "@tag1, @tag2, @tag3, ..." format too.
* <br></br>
* This runner works with either of them or both combined. Let's say You have passed '@smoke' tag in @CucumberOptions annotation which have 100 scenarios, then additionally you can also pass a runtime tag "@Login" and filter again.
*/
@CucumberOptions( features = "src/test/resources/features/",
glue = { "stepDefinitions", "hooks" },
plugin = { "pretty", "com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:" },
tags = "" ) //Pass tags here as usual
public class CucumberRunnerTest extends AbstractTestNGCucumberTests
{
@DataProvider
@Override
public Object[][] scenarios()
{
Object[][] scenarios = super.scenarios();
String dynamicTags = System.getenv("tags"); //passed from Pipeline
//Or add any other sources you want to get the tags from
if ( dynamicTags != null && !dynamicTags.equals("") )
{
List<Object> filteredScenarios = new ArrayList<>();
for ( int i = 0; i < scenarios.length; i++ )
{
PickleWrapper pickleWrapper = ( PickleWrapper ) scenarios[i][0];
List<String> tags = pickleWrapper.getPickle().getTags();
if ( dynamicTags.contains(", ") )
{
String[] tagsArray = dynamicTags.split(", ");
for ( String tag : tagsArray )
{
if ( tags.contains(tag) )
{
filteredScenarios.add(scenarios[i]);
break;
}
}
}
else
{
if ( TagExpressionParser.parse(dynamicTags).evaluate(tags) ) filteredScenarios.add(scenarios[i]);
}
}
return filteredScenarios.toArray(new Object[0][0]);
}
return scenarios;
}
}
Try this once. Please, upvote when it works so that more people can easily find and use the latest code.

- 1
- 1