10
votes

The ruby version of cucumber supports a global before hook. An *.rb file placed in the features/support directory gets apparently called only once, before any and all scenarios run. See https://github.com/cucumber/cucumber/wiki/Hooks#global-hooks

That seems to be a great way to make sure a database (used in read-only during tests) gets populated (and thus is in a known state) before any tests run.

Is there a similar feature available for the Java version of cucumber?

4

4 Answers

4
votes

Please follow this link. this a workaround for @BeforeAll and @AfterAll

https://github.com/cucumber/cucumber-jvm/issues/515

3
votes

There is no such feature natively in Cucumber JVM (see https://github.com/cucumber/cucumber-jvm/issues/515).

However, there are a couple of workarounds:

  • Use the hooks of your test framework:
    • @BeforeAll and @AfterAll for JUnit 5,
    • @BeforeClass and @AfterClass for JUnit 4
  • Use a Cucumber Before hook for lazy singleton initialization and a JVM shutdown hook for teardown
  • Implement a Cucumber EventListener and subscribe to TestRunStarted and TestRunFinished events
  • Use the integration test lifecycle features of your build framework, e.g. Maven's pre-integration-test, integration-test, post-integration-test phases and the maven-failsafe-plugin.

You will also have to solve the issue of injecting the results of such a setup step (e.g. random port numbers) into your tests.

I wrote a blog article to cover all details: https://metamorphant.de/blog/posts/2020-03-10-beforeall-afterall-cucumber-jvm-junit/

0
votes

As far as I know global hooks are not supported by Cucumber-JVM. However, you could try (tagged) hooks, @Before annotations and as a work-around static fields. Have a look here for an example.

0
votes

I have solved this problem a little bit using a class rule. Let's say that we wanted our cucumber test to start a single TestContainers container that we were testing. Let's say we were testing REDIS (we're not but it's a simple example).

@RunWith(Cucumber.class)
@CucumberOptions(...)
public class TestRunner {
    @ClassRule
    static GenericContainer REDIS = new GenericContainer<>("redis:5.0.3-alpine")
        .withExposedPorts(6379);

    // obviously we weren't testing redis, but this gives you the idea of a container
}

The above causes the TestContainers class GenericContainer to be initialized before the cucumber lifecycle and then torn down afterwards. You can write your own custom JUnit rule, extending TestRule and use it to decorate the execution of tests with your own custom set up.

A common problem with this is that you have to somehow get access to the objects created at this point in the lifecycle from things created on a per-scenario basis. However, given that this lifecycle is part of the static state of the Cucumber test suite, you can just access the test rule object via the static field of the suite.

I have a blog post on this here - https://codingcraftsman.wordpress.com/2020/01/20/extending-the-cucumber-test-lifecycle/