Extending the Cucumber Test Lifecycle


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:

public class TestRunner {
    static GenericContainer REDIS = new GenericContainer<>("redis:5.0.3-alpine")

    // 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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s