Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Junit Platform] Deprecate @Cucumber in favour of @Suite #2362

Merged
merged 3 commits into from
Aug 18, 2021

Conversation

mpkorstanje
Copy link
Contributor

@mpkorstanje mpkorstanje commented Aug 16, 2021

The CucumberJUnit Platform Engine has been updated to 1.8. With JUnit 5.8 comes
the junit-platform-suite engine. This engine allows the
programmatic declaration of test suites.

So it is now possible to write the following JUnit 4 test:

package com.example;

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class)
@CucumberOptions(glue = "com.example.application", features = "classpath:com/example/application")
public class RunCucumberTest {

}

As a declarative JUnit 5 test suite:

package com.example;

import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;

import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;

@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("com/example/application")
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example.application")
public class RunCucumberTest {

}

In combination with the before-all and after-all hooks this allows for a
feature-complete migration from JUnit 4. And allows us to deprecate
the @Cucumber annotation in favour of @Suite.

Fixes: #2331

@mpkorstanje mpkorstanje changed the base branch from main to v7.x.x August 16, 2021 17:38
@mpkorstanje mpkorstanje changed the title Junit platform deprecate cucumber annotation [Junit Platform] Deprecate @Cucumber in favour of @Suite Aug 16, 2021
@mpkorstanje mpkorstanje added this to the v7.0.0 milestone Aug 16, 2021
@mpkorstanje mpkorstanje force-pushed the junit-platform-deprecate-cucumber-annotation branch from d488ff0 to 9a1a1b8 Compare August 16, 2021 18:13
@mpkorstanje
Copy link
Contributor Author

Waiting for JUnit 5.8 to be available.

@mpkorstanje mpkorstanje marked this pull request as draft August 16, 2021 18:14
@codecov
Copy link

codecov bot commented Aug 16, 2021

Codecov Report

Merging #2362 (bd2cb04) into v7.x.x (2c97e81) will decrease coverage by 0.09%.
The diff coverage is 0.00%.

❗ Current head bd2cb04 differs from pull request most recent head bacea23. Consider uploading reports for the commit bacea23 to get more accurate results
Impacted file tree graph

@@             Coverage Diff              @@
##             v7.x.x    #2362      +/-   ##
============================================
- Coverage     83.33%   83.24%   -0.10%     
+ Complexity     2324     2323       -1     
============================================
  Files           296      296              
  Lines          8301     8309       +8     
  Branches        737      737              
============================================
- Hits           6918     6917       -1     
- Misses         1098     1103       +5     
- Partials        285      289       +4     
Impacted Files Coverage Δ
...unit/platform/engine/CucumberEngineDescriptor.java 55.55% <0.00%> (-23.40%) ⬇️
.../src/main/java/io/cucumber/guice/GuiceFactory.java 90.90% <0.00%> (-9.10%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2c97e81...bacea23. Read the comment docs.

@mpkorstanje mpkorstanje force-pushed the junit-platform-deprecate-cucumber-annotation branch from 9a1a1b8 to e30e0d3 Compare August 17, 2021 21:23
@mpkorstanje mpkorstanje force-pushed the junit-platform-deprecate-cucumber-annotation branch from e30e0d3 to ff12508 Compare August 18, 2021 13:52
@mpkorstanje mpkorstanje marked this pull request as ready for review August 18, 2021 13:58
@mpkorstanje mpkorstanje merged commit dcb0d66 into v7.x.x Aug 18, 2021
@mpkorstanje mpkorstanje deleted the junit-platform-deprecate-cucumber-annotation branch August 18, 2021 14:25
@aslakhellesoy
Copy link
Contributor

This sounds great! When something is deprecated I think docs should etc should document the new way rather than the old.

We need a ticket to keep track of what needs to be updated. Quick brain dump:

  • docs repo
  • skeleton repo
  • archetype repo
  • this repo (in case @cucumber is still ised)

@mpkorstanje
Copy link
Contributor Author

The @Cucumber annotation was never documented outside this repository. It was a workaround to get Cucumber going with JUnit5 and Surefire/Gradle.

We can replace JUnit 4 with JUnit 5 now in the docs.cucumber.io though.

archetype repo

Part of this repo. Already covered.

skeleton repo

https://github.com/cucumber/cucumber-java-skeleton/pull/64/files

docs repo

Only thing left to do.

@davidghiurco
Copy link

davidghiurco commented Nov 17, 2021

package com.example;

import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;

import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;

@suite
@IncludeEngines("cucumber")
@SelectClasspathResource("com/example/application")
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example.application")
public class RunCucumberTest {

}

@mpkorstanje For my use-case, I need to be able to run RunCucumberTest class from a "fat-jar" (created using maven-shade-plugin). The plugin requires a main method be specified:

<build>
<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>shade</goal>
                </goals>
                <configuration>
                    <shadedArtifactAttached>true</shadedArtifactAttached>
                    <shadedClassifierName>jar-with-dependencies</shadedClassifierName>
                    <createDependencyReducedPom>false</createDependencyReducedPom>
                    <transformers>
                        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                            <mainClass>com.my.company.package.RunCucumberTest</mainClass>
                        </transformer>
                    </transformers>
                </configuration>
            </execution>
        </executions>
    </plugin>
</plugins>
</build>

Linking the class name RunCucumberTest (as you currently wrote it) as the main method class to maven-shade-plugin, compiling the fat jar, and trying to run it will yield a "Main method not present or cannot be found" error at runtime.

Including an empty main method within class RunCucumberTest:

@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("com/example/application")
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example.application")
public final class RunCucumberTest {
    public static void main(String[] args) {}
}

will do nothing when run from the fat-jar (for obvious reasons).

Back in JUnit 4 platform, my solution to this was:

import org.junit.runner.JUnitCore;
...
public final class RunCucumberTest {
    public static void main(String[] args) {
        JUnitCore.main(RunCucumberTest.class.getName());
    }
}

What is the correct JUnit 5 main() invocation?

References: https://stackoverflow.com/questions/66563561/run-test-suite-class-with-junit-5-programmatically

@mpkorstanje
Copy link
Contributor Author

The JUnit 5 equivalent of JUnitCore.main is the JUnit Platform Console Launcher.

https://junit.org/junit5/docs/current/user-guide/#running-tests-console-launcher

Cucumber also has a main method of it's own: io.cucumber.core.cli.Main.

@davidghiurco
Copy link

davidghiurco commented Nov 17, 2021

Cucumber also has a main method of it's own: io.cucumber.core.cli.Main.

This seems to work:

import io.cucumber.core.cli.Main;
...
@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("com/my/company/package/features")
@ConfigurationParameters({
    @ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "pretty"),
    @ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "html:target/report/cucumber.html"),
    @ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "json:target/report/cucumber.json"),
    @ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "junit:target/report/cucumber.xml"),
    @ConfigurationParameter(key = FILTER_TAGS_PROPERTY_NAME, value = "not @Ignore"),
    @ConfigurationParameter(key = PLUGIN_PUBLISH_QUIET_PROPERTY_NAME, value = "true")
})
public final class RunCucumberTest {
    public static void main(String... args) {
        Main.main();
    }
}

However, if main() is called with no parameters, the @ConfigurationParameters array isn't taken into account, and I lose that configuration when running from fat-jar.

Is there a way to pass a reference to the RunCucumberTest class so that its configuration is taken into account?
That's what was happening when calling JUnitCore.main(RunCucumberTest.class.getName());

I don't see such a possibility in the method signatures of io.cucumber.core.cli.Main:

image

@mpkorstanje
Copy link
Contributor Author

Either you run Cucumber directly through it's own main method. Or you run Cucumber through JUnit 5.

If you run Cucumber directly, any instructions for JUnit related to running Cucumber will be ignored. If you run Cucumber directly you don't need and can remove any and all parts related to JUnit 5 from your project.

If you do run Cucumber through JUnit 5 and you want to run JUnit 5 from a main method you have to use the Console Launcher provided by JUnit 5.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants