Feature files discovery in cucumber-junit-platform-engine - java

In cucumber-junit library I use #CucumberOptions to define feature files location:
package com.mycompany.cucumber;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;
#RunWith(Cucumber.class)
#CucumberOptions(
plugin = ...,
features = "classpath:.", // my java step definitions are in package com.mycompany.cucumber
// but feature files directly in test resources
// resources/is_it_friday_yet.feature
tags = ...,
glue = ...
)
public class CucumberRunner {
}
I'm running my tests with custom gradle task cucumberTest
cucumberTest {
useJUnitPlatform()
}
After migrating to cucumber-junit-platform-engine #CucumberOptions are no longer supported.
package com.mycompany.cucumber;
import io.cucumber.junit.platform.engine.Cucumber;
#Cucumber
public class CucumberRunner {
}
I can make it work with replacing plugin, tags, glue options with properties cucumber.filter.tags, cucumber.glue, cucumber.plugin.
What about features property? It works fine if I change feature files location to match package name i.e. resources/com/mycompany/cucumber/is_it_friday_yet.feature. Still this is a simple case and I have many more test packages which are not placed in the same locations as source code and I cannot move them.

In cucumber-jvm v7 the #Cucumber annotation is deprecated and you're encouraged to use the regular #Suite annotation. This works for me:
#Suite
#IncludeEngines("cucumber")
#SelectClasspathResource("features")
#ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.mycompany.cucumber")
public class CucumberIT {
}
It picks up all my .feature files under the features/ dir in my resources folder (classpath)
Purpose of annotations:
#Suite - annotation from JUnit 5 to make this class a run configuration for test suite.
#IncludeEngines("cucumber") - tells JUnit 5 to use Cucumber test engine to run features.
#SelectClasspathResource("features") - to change the location of your feature files (if you do not add this annotation classpath of the current class will be used).
#ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.mycompany.cucumber") - this annotation specifies the path to steps definitions (java classes).
Docs: https://github.com/cucumber/cucumber-jvm/tree/main/junit-platform-engine#suites-with-different-configurations
There are various other #Select* annotations supported by junit-platform, I assume those work as well (though they're marked as experimental so subject to change): https://junit.org/junit5/docs/current/user-guide/#api-evolution-experimental-apis

Gradle doesn't support non-class based test engines. However you can create a custom task that uses the JUnit Platform ConsoleLauncher. You can then use the Junit 5 selectors that are supported by Cucumber to select your features. For example the FileSelector with --select-file.
val consoleLauncherTest by tasks.creating(JavaExec::class) {
dependsOn("testClasses")
val reportsDir = file("$buildDir/test-results")
outputs.dir(reportsDir)
classpath(sourceSets["test"].runtimeClasspath)
main = "org.junit.platform.console.ConsoleLauncher"
args("--select-file", "path/to.feature")
args("--details", "tree")
args("--reports-dir", reportsDir)
}

Related

Why Junit TestRunner cannot find the features?

I am working with cucumber and selenium project and I am trying to run the test by a Junit Test Runner. Here is the complete code (make sure you have lombok in your IDE). And here is my test runner:
#RunWith(Cucumber.class)
#CucumberOptions(
features = {"src/test/resources/features" },
monochrome = true,
plugin = {
"pretty",
"com.cucumber.listener.ExtentCucumberFormatter:target/report.html"
},
tags = {"#all"},
glue = {"stepDefinitions"}
)
public class TestRunnerJUnit {
#AfterClass
public static void setup() {
Reporter.setSystemInfo("User Name", System.getProperty("user.name"));
Reporter.setSystemInfo("Time Zone", System.getProperty("user.timezone"));
Reporter.setSystemInfo("Machine", "Windows 10" + "64 Bit");
Reporter.setTestRunnerOutput("Sample test runner output message");
}
}
The point is, when i run the test using the test runner, it finds the feature file, but it does not find any Scenario inside it. Here is the output of the run:
#all
Feature:
As a customer, I should be able to register for insurance.
0 Scenarios
0 Steps
0m0.000s
if i run the test directly using the feature file (by right click on it Run as Cucumber then it works well. But, i need to run my test by test runner)
I had a chance to pull your code base and look into the code.
the issue you are running into is something to do with extent library. you are providing feature name in a new line and which extent library can't understand that. write feature name in same line and it should solve your problem
Feature: As a customer, I should be able to register for insurance.
I also suggest you to use newer version of cucumber (Cucumber-JVM v4+) libraries which have concurrent execution support( under single JVM) and current library which you are using going to span up multiple JVM instances depending on your configuration

Modify CucumberOptions tags when running Cucumber in Java

I was wondering if there was a way to modify CucumberOptions tags while Cucumber is running?
I'm not sure if this is possible or not but I was wondering if there was a way to modify tags while Cucumber is running. In my example code, I would like to add another tag "#Login" once Cucumber runs. I am trying to setup a configuration where I can select which feature I want to run without going into the Runner class.
Settings Class
String AddTags = "#Login";
set = new HashMap<String, String>(){
{put("Tags", AddTags);
Runner
import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
#RunWith(Cucumber.class)
#CucumberOptions (features="src/test/cucumber/features",
tags = "#Smoke", //For instance, once cucumber runs I want to add
tag "#Login". //So something like adding Settings.set.get("Tags");
plugin = {"pretty", "html:target/cucumber-
htmlreport","json:target/cucumber-report.json"}
)
public class Runner {
}
Not sure if this is possible with Cucumber but wanted to ask.
You can use Tag expressions to combine several tags, for example:
**Expression Description**
#fast Scenarios tagged with #fast
#wip and not #slow Scenarios tagged with #wip that aren’t also tagged with #slow
#smoke and #fast Scenarios tagged with both #smoke and #fast
#gui or #database Scenarios tagged with either #gui or #database
What about using a list of tags?
tags = "#Smoke,#Login"

IntelliJ Idea: JUnit Test Class template depending on condition

I often write tests of different types. Depending on test type it might have different setup.
For instance all my service tests have the following annotation under class declaration:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = NONE)
All controller tests have these annotations:
#RunWith(SpringRunner.class)
#WithMockUser
#WebMvcTest(controllers = MyController.class)
Another tests have different setup, etc.
Every time when I create a test I have to copy-paste this part from another test.
I'm looking for a solution that will help me automate this process in IntelliJ Idea.
Q: Is there any way to define JUnit Test Class templates which work differently depending on the type of the test?
Let's say class name ends with word "Service" - its generated test should use one template, if class name ends with "Controller" - its test should use another one, etc.
It is also possible to detect test type by package name or some other conditions like class content.
The JUnit code generation templates can be found under Settings > File And Code templates > Code.
You can't really create separate code templates, but what you could do is add logic to the existing templates. They use Velocity based directives.
So if, for example, we take the existing JUnit 4 template:
import static org.junit.Assert.*;
#parse("File Header.java")
public class ${NAME} {
${BODY}
}
We can modify it to the following:
import static org.junit.Assert.*;
#if($CLASS_NAME.contains("Service"))
//Import whatever you need for services here.
#end
#if($CLASS_NAME.contains("Controller"))
//Import whatever you need for controllers here.
#end
#parse("File Header.java")
#if($CLASS_NAME.contains("Controller"))
#set($CLASS_SUFFIX = ".class" )
#RunWith(SpringRunner.class)
#RunWithMock
#WebMvcTest(controllers = $CLASS_NAME$CLASS_SUFFIX)
#end
#if($CLASS_NAME.contains("Service"))
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = NONE)
#end
public class ${NAME} {
${BODY}
}
This way if you generate a new JUnit 4 test class through the context menu (hit alt-enter on the class name of the class you want to test and generate new test) it will generate different output if the name of the class to test contains 'Controller' or 'Service'. You might want to change that to endswith instead of contains depending on whatever naming conventions you use.
I've left out the actual import statements in both cases, but I'm sure you'll be able to add those.

How can I set cucumber feature path using a string from another class?

here's my question:
I'd like to set the 'features' path on my cucumber configuration class using a string from another class. I have a lot of different tests and I always need to change the feature path manually in each one, I already tried to create another class with a string, where I can set the paths that I use most (because I work on two different laptops), but I couldn't call the string inside the #CucumberOptions annotation. Is there some way to do it?
The way it is now:
#RunWith(Cucumber.class)
#CucumberOptions(
plugin = {"json:../evidence/output/report_data.json", "html:../evidence/output/"}
, features = {"../feature/finish_orders.feature"}
The way I want it
#RunWith(Cucumber.class)
#CucumberOptions(
plugin = {"json:../evidence/output/report_data.json", "html:../evidence/output/"}
, features = {STRING_WHERE_IS_THE_PATH}
You should have all your feature files stored in one place. It does not have to be the same directory and can be nested. If you want to execute a specific scenario you can use tagging. For example, you can set your #CucumberOptions like this:
#CucumberOptions(
features = {"classpath:test_features"},
tags = {"#wip"})
and tag the scenarios you want to run with #wip. It will only execute the #wip tagged scenarios.

BDD Cucumber tests via jUnit

I there any examples for runing cucumbers via jUnit manually?
I have a simple empty class with #RunWith(Cucumber.class) which has all my feature files.
import cucumber.junit.Cucumber;
import org.junit.runner.RunWith;
#RunWith(Cucumber.class)
public class RunCukesTest {
}
And simple junit test running it:
#Test
public void cucumberFirstPartTests()throws Exception{
Cucumber cucumber = new Cucumber(RunCukesFirstPart.class);
RunNotifier notifier = new RunNotifier();
cucumber.run(notifier);
}
Is there any examples at all for filtering manually tests, using runner scheduler and descriptions of tests for cucumbers? Watched documentation, but for me it is not enough. I will appreciate any links. Thank you.
You can mark each Scenario/Feature with any number of tags, using #TAGNAME
Given that, you can tell the runner to run a selected set of tags
#RunWith(Cucumber.class)
#Cucumber.Options(tags = {"#TAGNAME"})
Is that what you were after?

Categories

Resources