How to translate Maven cucumber-jvm junit #CucumberOptions(..) to Eclipse Run Configuration - java

My RunCukeTest class looks like:
package runsupport;
import ....
#RunWith(Cucumber.class)
#CucumberOptions(
monochrome = true,
features = "classpath:features",
plugin = {"pretty", "html:target/cucumber-html-report", "json:target/cucumber.json"},
glue = { "classpath:steps", "classpath:runsupport" },
tags = {"#search"}
)
public class RunCukesTest{
}
How do I convert this to mvn test -Dcucumber.options="" format so that I can run it from the Goals line of a Maven Build run configuration? I want to be able to change the tags on the run configuration rather than having to edit the RunCukeTest class each time.

The answer turned out to be:
clean test -Dcucumber.options="--tags #search --monochrome --plugin pretty:STDOUT --plugin html:target/cucumber-html-report --plugin json:target/cucumber.json --glue steps --glue runsupport classpath:features"
Note that since I have two glue paths that I needed two --glue statements. Also note that only the package name of the two -glue paths were specified.
Further note that STDOUT needed to be specified on --plugin pretty:STDOUT.
Finally note that the feature keyword was dropped completely. The path specified at the end (without a keyword) tells cucumber-jvm where to find the feature files.
If you get any of this wrong cucumber-jvm gives you cryptic error messages. I thought that I would post this for the next person to save him or her an hour or two.
BTW, to get a Maven Build configuration in Eclipse, click on Run > Run Configurations... On the left pane double-click Maven Build. A default Maven Build configuration is created. Give it a good name and on the Goals line paste your clean test -Dcucumber.options line. It wouldn't hurt to click on the JRE tab and make sure that the correct JDK is being used. Back on the Main tab, press Apply, press Run. It completely overrides the #CucumberOptions line in your RunCukesTest (or whatever you named it) class. It is a lot easier to run tests this way and you aren't confusing git with unnecessary local file edits.

Related

Include / exclude tests with Maven Surefire + JUnit5 from command line

I want to run the build for Apache James which has a huge test suite that is running very long due to tests that irrelevant to me, e.g. tests concerning RabbitMQ. Thus I'd like to exclude those and I want to do so from the command line (not by editing POMs). I'm using Maven 3.6.3 on Java 11 OpenJDK. The project uses JUnit5 and maven-surefire-plugin 2.22.2.
Now, I would expect the following to work:
For example, to run only test methods in the org.example.MyTest test
class you can execute mvn -Dtest=org.example.MyTest test from the
command line.
But it doesn't work. In fact, as soon as I set the test parameter to anything else than an empty string, all tests will be skipped. I tried some of the syntax that is supposedly supported...
mvn package -Dtest=*
mvn package -Dtest=".*"
mvn package -Dtest=\!SomethingFishy
mvn package -Dtest='!MavenHeadache'
mvn package -Dtest='!%regex[.*HelpMe.*]'
...but the result is always the same:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test
(default-test) on project testing-base: No tests were executed!
(Set -DfailIfNoTests=false to ignore this error.) -> [Help 1]
I'm running the package goal, as it does the full build, but test behaves the same. Also tried specifying -Dincludes=... / -Dexcludes=..., which had no effect at all: All tests are executed regardless and the parameters don't even show up in the output of mvn -X .... This behavior doesn't change when update maven-surefire-plugin to the latest version which is 3.0.0-M5.
Do I understand something wrong here? How can i specify inclusions/exclusions in this setup?
Update: It looks like this is caused by nested projects and/or James' project structure in particular. If I enter a "leaf project", e.g. core, then inclusions/exclusions begin to work:
cd core
mvn test -Dtest=HostTest # will only run HostTest, as expected
mvn test -Dtest=\!HostTest # will run all tests but HostTest, as expected
As suggested by RobertScholte, I have looked at the maven-surefire-plugin configuration, but couldn't find anything that seems to be related to this behavior.
The error message tells what you need to know: in project testing-base which is the first to run, there's no test matching your pattern, so it fails to ensure you won't have a false impression of success.
It then suggests to use -DfailIfNoTests=false option to let maven ignore modules that don't have any test matching the pattern (it's probably what you need).

How to glue multiple steps directories to a cucumber test in Intellij?

I have a Cucumber scenario whose steps are defined in multiple Step files, as opposed to only having only one. If I decide to run the test using Intellij I go to run/debug configurations menu and the form provides a field named glue which enables me to specify the steps package.
So far I was able to run the scenarios that have all steps defined in the same Steps file, but I was unable to figure out how to do it for the scenarios that require multiple steps files located in different packages. I've tried a csv approach but without success. Does anyone know what I am missing? Thank you for your help.
There are few ways to configure the glue paths with Cucumber.
As a cucumber.properties file in the root package (usually src/test/resources/cucumber.properties):
cucumber.glue=com.example.steps1,com.example.steps2
Via the command line
--glue com.example.steps1 --glue com.example.steps2
Or with the #CucumberOptions annotation.
#RunWith(Cucumber.class)
#CucumberOptions(glue ={"com.example.steps1", "com.example.steps2"})
public class RunCucumberTest {
}
When using IDEA you have to separate the glue packages with a new line or space (not a comma!).
com.example.steps1
com.example.steps2
And if you are on a recent version of Cucumber (6+) you don't have to provide the glue at all. Cucumber will search the class path by default.
M.P. Korstanje's answer provides very useful tips but not for this specific case. What worked for me was:
Specify the parent package as opposed to several distinct sub-packages (e.g. use only com.example instead of both com.example.steps1, com.example.steps2) in the Glue field
Select the correct module in the Use classpath of module field.

How to run all JUnit tests with Bazel

I have been trying to run all JUnit tests in a directory with Bazel. As far as I know, the java_test rule is only capable of running a specific class. However, I'm looking for behavior more like mvn test which runs all JUnit tests in the project. How can I accomplish this?
The typical way to organize this is to have a java_test rule per Java test class, or per group of related Java test classes. Then java_tests can be grouped together using test_suite, if that's something you want to do.
You can run all tests in a package with:
bazel test //some/package:all
or in a package and its subpackages:
bazel test //some/package/...
or in the entire workspace:
bazel test //...
More about target patterns: https://docs.bazel.build/versions/master/guide.html#target-patterns
If you just want a java_test that runs all the tests in a directory, you can do something like
java_test(
name = "tests",
srcs = glob(["*Test.java"]),
deps = [ ..... ],
)
but that may or may not be the right thing to do. In particular, if you want to just run one test or one test method (e.g. using --test_filter), bazel will still build all the java_test's dependencies. Also, note that globs only glob within a build package, and won't cross over into other packages.

Using JUnit 5 with Java 9 without Maven or Gradle

The Description:
I would like to create a JUnit test using JUnit 5 in Eclipse (Oxygen 4.7.1a).
This JUnit test should be inside a seperate src folder called Test. However, I ran into the following problems as I'm new to JUnit and Java 9.
I do not want to use build tools like Gradle or Maven for this.
The Problem:
As I've got two different src folders, one for the projects src and one for the test cases:
Do I need two module-info.java files? (one for each src folder)
Which modules are required in my module-info.java file for JUnit 5 to work?
In general there is no need to modularize your test code (at least I can't think of a valid reason, maybe someone could give a satisfactory counter-example). Only one module-info.java file can (after all, it's not even required to modularize your main code) be present in your main code under src.
Since the module-info.java file will be only in your main source directory and not in the test source directory, then logically it should not depend on the JUnit module. So the questions now become how to compile and run the JUnit test classes by relying on the module (that represents the system under test) and the JUnit module.
To do that, you'll need to use the new options provided by the javac and java:
So assuming you have the following tree:
src
module-info.java (declares a module called "my.module")
mypackage
MyClass.java
test_src
mypackage
MyClassTest.java
lib/junit-platform-console-standalone.jar
(note: specifically for JUnit 5, you can use the junit-platform-console-standalone artifact that contains the core JUnit engine and allows running tests in the console; see the user guide)
then you can compile the code as follows:
cd root_dir
javac -d mods/my.module src/module-info.java src/mypackage/MyClass.java
cd test_src
javac -d test_out --module-path ../mods;../lib/junit-platform-console-standalone.jar \
--add-modules org.junit.platform.console.standalone,my.module --patch-module my.module=. \
--add-reads my.module=org.junit.platform.console.standalone mypackage/MyClass.java
and you can run the compiled test class:
cd test_src/test_out
java --module-path=../../mods;../../lib/junit-platform-console-standalone.jar \
--add-modules my.module,org.junit.platform.console.standalone \
--add-reads my.module=org.junit.platform.console.standalone \
--patch-module my.module=. \
--add-opens my.module/test=org.junit.platform.console.standalone \
org.junit.platform.console.ConsoleLauncher test.MyClassTest
Awkward commands but that's the cost of not using Maven. I advise you to read about these options in the command documentation after understanding the concept of a module path. An important thing to note here are a couple of options:
--patch-module my.module=.
This is needed because the example test code has the same package (mypackage) as the module my.module. Without it, the module system will complain.
--add-reads my.module=org.junit.platform.console.standalone
This makes junit required by my.module even though it was not declared in module-info.java.
org.junit.platform.console.standalone is the name of the automatic module and is derived from the Jar manifest (as is the case with JUnit 5), otherwise from the name of the Jar file (e.g. in the case of JUnit 4).
Also note that this is what Maven probably does behind the scenes when compiling and running unit tests (see this issue for an equivalent plugin configuration that manually does the above).
What if for some reason, you also want to modularize your unit tests?
In this case, since in the example above the unit tests share the same package, you can include them in my.module and add a requirement to JUnit:
module my.module {
exports mypackage;
requires org.junit.platform.console.standalone;
}
If the unit tests were in a different package, you can also split them into two modules (two module-info.java), a my.module and a my.test.module where only the latter requires JUnit.
If you do include test classes in a module, then in the above commands, you don't need --add-reads and --patch-module.
A reason for the tests being in a module on their own is hexagonal architecture. The test module is a driver adapter swappable with other adapters that run the business logic too.
In my case I'm gonna do it using jaba 9 without maven too.
Here's my article about hexagonal architecture:
https://softwarecampament.wordpress.com/portsadapters/

Setting properties via Maven command line

I'm confused about the correct way to set a property for some unit tests via the command line when using Maven. There are a number of questions (e.g. Specifying Maven memory parameter without setting MAVEN_OPTS environment variable, Is there a way to pass jvm args via command line to maven?, How to set JVM parameters for Junit Unit Tests?) that touch on this subject but none have the answer I'm looking for.
I want to set the property java.util.logging.config.class to some value but I don't want to set the MAVEN_OPTS environment variable.
I can configure the surefire plugin in my pom file with the property:
<argLine>-Djava.util.logging.config.class=someClass</argLine>
so that it is set every time the test phase is run.
However, if I remove the setting from the pom file and add the following to the command line:
mvn package -DargLine="java.util.logging.config.class=someClass"
then the following error in the test phase is reported and the build fails:
Error: Could not find or load main class java.util.logging.config.class=someClass
If I run the following from the command line:
mvn package -Djava.util.logging.config.class=someClass
then the following error is reported at the beginning of the build but the build and tests are successful:
Logging configuration class "someClass" failed
java.lang.ClassNotFoundException: someClass
I don't really understand the behaviour. Can someone enlighten me?
Yes, you should have
mvn package -DargLine="-Djava.util.logging.config.class=someClass"
Notice the addition of -D inside the argLine.
Let's explain why. argLine is indeed an attribute of the maven-surefire-plugin with the corresponding user property argLine. This means that you can set this property directly on the command line with -DargLine. But then, the value of that property is -Djava.util.logging.config.class=someClass. This is exactly what you had when you configured the plugin in the POM directly with
<argLine>-Djava.util.logging.config.class=someClass</argLine>
Additionally, when you call
mvn package -Djava.util.logging.config.class=someClass
then you are not setting the argLine property. You are adding a system property.
Regarding your approach to configuring tests
If you want to pass in configuration to your tests, use for example a file in src/test/resources/myTestConfig.xml. Or use the enhanced features of Test-ng. Your tests will have no value on the centralized build server, or those who want to run/test your code, where config values can't be changed (easily).
The recommended usage of command-line arguments for Maven is for configuring the Maven plugins, build environment and Java config for the build.
Use as little features, config and plugins as possible. Or you'll face a ton of issues down the line, and the tweak-all-you-want-A-standardized-build-doesn't-mean-sh*t-for-me-Gradle will feel more comfortable.

Categories

Resources