Software Development

Extending the Cucumber Test Lifecycle

Overview

This article is about two things:

  • How do I make the beforeAll and afterAll lifecycle events happen in Cucumber?
  • How can I use TestContainers to set up the system under test before a Cucumber test runs?

No, YOU’RE trying to do SEO on YOUR blog.

That Cucumber Lifecycle…

Cucumber’s lifecycle includes:

  • Before hook – before each scenario
  • After hook – after each scenario
  • Before step
  • After step

And that’s about it… you can conditionally run hooks.

What if there’s a Grand Lifecycle?

You mean, what if you need to start up the system under test on a per test run basis, not on a per scenario basis? Or do some post testing cleanup?

It seems that this is not covered by cucumber itself.

Life has a way of needing this sort of feature.

Is there a way to run Before All and After All in Cucumber?

Assuming you’re using JUnit 4, then the following will apply. I would expect a JUnit5 equivalent, but have not tested it.

What you need to know:

  • The Cucumber JUnit runner is based on JUnit4 ParentRunner
  • This class has support for the JUnit @Rule annotation. In particular @ClassRule
  • While Cucumber itself has no support for the additional lifecycle, it turns out the internals of JUnit4 will honour @ClassRule rules
  • So if you wanted to create some behaviour around the execution of your tests, you need to create a TestRule object as a static field of the cucumber suite class and add @ClassRule to it.

A Real Life Scenario

We had an app which needed to be deployed inside docker in order to run our automation pack. We could use TestContainers to achieve this before all tests ran, and that would also tidy up the docker resources at the end of the test run.

As a test containers container is, itself, a TestRule it was pretty trivial to inject one into the test:

1
2
3
4
5
6
7
8
9
@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
}

Inside the glue code, we could then reach back to the global object to ask it for the correct port number (as TestContainers puts containers on random exposed ports from the given logical port).

It’s That Easy

With this trick of using test rules, you can have that missing Cucumber lifecycle hook, and you can integrate a TestContainers element into the test.

Except… in real life I had a much more complex thing to do, so built a custom composite test rule to weave together the whole process, with the same use of @ClassRule to link it into the lifecycle.

And if you’re in JUnit5, think JUnit5 extensions, rather than rules, and there’ll be a way you can produce a custom extension to do much the same thing, or just get your extension annotations in the right order, and JUnit5 may do it all for you.

Published on Java Code Geeks with permission by Ashley Frieze, partner at our JCG program. See the original article here: Extending the Cucumber Test Lifecycle

Opinions expressed by Java Code Geeks contributors are their own.

Ashley Frieze

Software developer, stand-up comedian, musician, writer, jolly big cheer-monkey, skeptical thinker, Doctor Who fan, lover of fine sounds
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button