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

Add @BeforeAll and @AfterAll hooks #515

Open
aslakhellesoy opened this Issue May 2, 2013 · 114 comments

Comments

Projects
None yet
@aslakhellesoy
Contributor

aslakhellesoy commented May 2, 2013

People keep asking for BeforeAll and AfterAll hooks. I haven't had a big need for them myself, but it seems to me this would be sufficient:

public class GlobalHooks {
    private static boolean dunit = false;

    @Before
    public void beforeAll() {
        if(!dunit) {
            Runtime.getRuntime().addShutdownHook(afterAllThread);
            // do the beforeAll stuff...
            dunit = true;
        }
    }
}

If this doesn't cut it for you, please explain in this ticket, and maybe we'll add special support for it.

@mattwynne

This comment has been minimized.

Show comment
Hide comment
@mattwynne

mattwynne May 2, 2013

Member

Does that fire when the process dies, or just the current cucumber run? What if you wanted to do multiple runs without killing the process? (In an Aruba 5.2 stylee)

Member

mattwynne commented May 2, 2013

Does that fire when the process dies, or just the current cucumber run? What if you wanted to do multiple runs without killing the process? (In an Aruba 5.2 stylee)

@aslakhellesoy

This comment has been minimized.

Show comment
Hide comment
@aslakhellesoy

aslakhellesoy May 2, 2013

Contributor

It wouldn't be triggered by a VM shutdown. It would be part of the runner's life cycle and fire after the last scenario.

For Java I think they would have to be defined as static methods as well.

Contributor

aslakhellesoy commented May 2, 2013

It wouldn't be triggered by a VM shutdown. It would be part of the runner's life cycle and fire after the last scenario.

For Java I think they would have to be defined as static methods as well.

@tmertens

This comment has been minimized.

Show comment
Hide comment
@tmertens

tmertens May 2, 2013

What would happen if you try to embed data into the report in this
"BeforeAll" hook? It seems your example would work well for running some
code only once at the start of the scenarios, but any embedded would be
inserted into the first scenario that runs that code and not at the root
level of the report.

Furthermore, I supposed embed wouldn't work in the shutdown hook either in
the above case. Given scenario.embed is used for embedding data in
reports, I'm guessing there would have to be some new object reference in
order to embed data in the reports for @BeforeAll/@afterall hooks outside
of the scenarios.

Cheers,

-Tim

On Thu, May 2, 2013 at 6:46 AM, Aslak Hellesøy notifications@github.comwrote:

It wouldn't be triggered by a VM shutdown. It would be part of the
runner's life cycle and fire after the last scenario.

For Java I think they would have to be defined as static methods as well.


Reply to this email directly or view it on GitHubhttps://github.com/cucumber/cucumber-jvm/issues/515#issuecomment-17333288
.

tmertens commented May 2, 2013

What would happen if you try to embed data into the report in this
"BeforeAll" hook? It seems your example would work well for running some
code only once at the start of the scenarios, but any embedded would be
inserted into the first scenario that runs that code and not at the root
level of the report.

Furthermore, I supposed embed wouldn't work in the shutdown hook either in
the above case. Given scenario.embed is used for embedding data in
reports, I'm guessing there would have to be some new object reference in
order to embed data in the reports for @BeforeAll/@afterall hooks outside
of the scenarios.

Cheers,

-Tim

On Thu, May 2, 2013 at 6:46 AM, Aslak Hellesøy notifications@github.comwrote:

It wouldn't be triggered by a VM shutdown. It would be part of the
runner's life cycle and fire after the last scenario.

For Java I think they would have to be defined as static methods as well.


Reply to this email directly or view it on GitHubhttps://github.com/cucumber/cucumber-jvm/issues/515#issuecomment-17333288
.

@aslakhellesoy

This comment has been minimized.

Show comment
Hide comment
@aslakhellesoy

aslakhellesoy May 2, 2013

Contributor

What would happen if you try to embed data into the report in this "BeforeAll" hook?

From a BeforeAll/AfterAll hook you would have optional access to a Report object with similar embed methods as the Scenario object available to Before/After hooks. Embeddings embedded from a BeforeAll would end up at the top of the report, before the first scenario. Similar for embeddings embedded from AfterAll - they would end up in the report after the last scenario.

If you attempt to do a Scenario.embed from an AfterAll hook you would get an exception - the scenario would be "closed" by then.

Contributor

aslakhellesoy commented May 2, 2013

What would happen if you try to embed data into the report in this "BeforeAll" hook?

From a BeforeAll/AfterAll hook you would have optional access to a Report object with similar embed methods as the Scenario object available to Before/After hooks. Embeddings embedded from a BeforeAll would end up at the top of the report, before the first scenario. Similar for embeddings embedded from AfterAll - they would end up in the report after the last scenario.

If you attempt to do a Scenario.embed from an AfterAll hook you would get an exception - the scenario would be "closed" by then.

@mikquinlan

This comment has been minimized.

Show comment
Hide comment
@mikquinlan

mikquinlan May 3, 2013

We definitely have many uses for this. Currently we use a static
initialiser (which I think we got from this forum) to start up embedded
databases, Hadoop's Mini MR cluster among other things.

It would be good to have a clear annotation such as @BeforeAll and
@afterall rather than a specific method name with an @before tag.

On 2 May 2013 07:37, Aslak Hellesøy notifications@github.com wrote:

What would happen if you try to embed data into the report in this
"BeforeAll" hook?

From a BeforeAll/AfterAll hook you would have optional access to a Reportobject with similar embed methods as the
Scenario object available to Before/After hooks. Embeddings embedded from
a BeforeAll would end up at the top of the report, before the first
scenario. Similar for embeddings embedded from AfterAll - they would end
up in the report after the last scenario.

If you attempt to do a Scenario.embed from an AfterAll hook you would get
an exception - the scenario would be "closed" by then.


Reply to this email directly or view it on GitHubhttps://github.com/cucumber/cucumber-jvm/issues/515#issuecomment-17341593
.

We definitely have many uses for this. Currently we use a static
initialiser (which I think we got from this forum) to start up embedded
databases, Hadoop's Mini MR cluster among other things.

It would be good to have a clear annotation such as @BeforeAll and
@afterall rather than a specific method name with an @before tag.

On 2 May 2013 07:37, Aslak Hellesøy notifications@github.com wrote:

What would happen if you try to embed data into the report in this
"BeforeAll" hook?

From a BeforeAll/AfterAll hook you would have optional access to a Reportobject with similar embed methods as the
Scenario object available to Before/After hooks. Embeddings embedded from
a BeforeAll would end up at the top of the report, before the first
scenario. Similar for embeddings embedded from AfterAll - they would end
up in the report after the last scenario.

If you attempt to do a Scenario.embed from an AfterAll hook you would get
an exception - the scenario would be "closed" by then.


Reply to this email directly or view it on GitHubhttps://github.com/cucumber/cucumber-jvm/issues/515#issuecomment-17341593
.

@pranasblk

This comment has been minimized.

Show comment
Hide comment
@pranasblk

pranasblk May 13, 2013

+1. I want having multiple BeforeAll and AfterAll supported (opposite to not like World)

+1. I want having multiple BeforeAll and AfterAll supported (opposite to not like World)

@mikquinlan

This comment has been minimized.

Show comment
Hide comment
@mikquinlan

mikquinlan Jun 1, 2013

Any movement on this issue? I'd love to have it. Of course, I'm just one person. ;-)

Any movement on this issue? I'd love to have it. Of course, I'm just one person. ;-)

@aslakhellesoy

This comment has been minimized.

Show comment
Hide comment
@aslakhellesoy

aslakhellesoy Jun 1, 2013

Contributor

Those of you who need it - how about sending a pull request?

Contributor

aslakhellesoy commented Jun 1, 2013

Those of you who need it - how about sending a pull request?

@quantoid

This comment has been minimized.

Show comment
Hide comment
@quantoid

quantoid Jun 4, 2013

Contributor

+1 because the trick above won't work for AfterAll

Contributor

quantoid commented Jun 4, 2013

+1 because the trick above won't work for AfterAll

@paoloambrosio

This comment has been minimized.

Show comment
Hide comment
@paoloambrosio

paoloambrosio Jun 5, 2013

Member

@quantoid It's not a trick, it's Java! Why do you say that it does not work for AfterAll? The only Issue I see is with reports.

The @AfterAll hook would be the afterAllThread variable in Aslak's code.

Added this snippet to the Java Hello World Example:

    @Before
    public void beforeAll() {
        if(!dunit) {
            Runtime.getRuntime().addShutdownHook(new Thread() {
                public void run() {
                    System.out.println("snake!");
                }
            });
            System.out.println("badger");
            dunit = true;
        }
    }

After changing the runner to use the progress formatter, when I run mvn test, I get the desired behaviour:

badger

.........
Tests run: 12, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.466 sec
snake!
Member

paoloambrosio commented Jun 5, 2013

@quantoid It's not a trick, it's Java! Why do you say that it does not work for AfterAll? The only Issue I see is with reports.

The @AfterAll hook would be the afterAllThread variable in Aslak's code.

Added this snippet to the Java Hello World Example:

    @Before
    public void beforeAll() {
        if(!dunit) {
            Runtime.getRuntime().addShutdownHook(new Thread() {
                public void run() {
                    System.out.println("snake!");
                }
            });
            System.out.println("badger");
            dunit = true;
        }
    }

After changing the runner to use the progress formatter, when I run mvn test, I get the desired behaviour:

badger

.........
Tests run: 12, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.466 sec
snake!
@quantoid

This comment has been minimized.

Show comment
Hide comment
@quantoid

quantoid Jun 5, 2013

Contributor

Sorry, I can see how it works in Java, I should've added "...in Groovy" but could be wrong about that too.

I'd want both 'all' hooks to be able to access variables that other glue can access, i.e. those in the Script scope.

Contributor

quantoid commented Jun 5, 2013

Sorry, I can see how it works in Java, I should've added "...in Groovy" but could be wrong about that too.

I'd want both 'all' hooks to be able to access variables that other glue can access, i.e. those in the Script scope.

@paoloambrosio

This comment has been minimized.

Show comment
Hide comment
@paoloambrosio

paoloambrosio Jun 5, 2013

Member

Same thing in the groovy-calculator example with BeforeAll and AfterAll, accessing the World object that contains shared variables.

class CustomWorld {

    def value = null
    def dunit = false

    // ...
}

Before() {
    if (!dunit) {
        dunit = true

        println "badger"
        value = "snake!" // sets the value in the World

        addShutdownHook {
            println value // reads the value from the World
        }
    }
}

Note that if you change the value variable in other steps, the shutdown hook is not going to print snake!, so the value is not determined when the closure is defined but when it is called (at the very end).

This change to a step will make the AfterAll closure print mushroom:

Then(~"the stored result should be (.*)") { double expected ->
    value = "mushroom"
    assert expected == result
}

Of course it works even if you define the value variable outside of the World object.

Member

paoloambrosio commented Jun 5, 2013

Same thing in the groovy-calculator example with BeforeAll and AfterAll, accessing the World object that contains shared variables.

class CustomWorld {

    def value = null
    def dunit = false

    // ...
}

Before() {
    if (!dunit) {
        dunit = true

        println "badger"
        value = "snake!" // sets the value in the World

        addShutdownHook {
            println value // reads the value from the World
        }
    }
}

Note that if you change the value variable in other steps, the shutdown hook is not going to print snake!, so the value is not determined when the closure is defined but when it is called (at the very end).

This change to a step will make the AfterAll closure print mushroom:

Then(~"the stored result should be (.*)") { double expected ->
    value = "mushroom"
    assert expected == result
}

Of course it works even if you define the value variable outside of the World object.

@quantoid

This comment has been minimized.

Show comment
Hide comment
@quantoid

quantoid Jun 6, 2013

Contributor

Awesome, thanks! Where does the addShutdownHook come from? There seem to be so many classes mixed in to the scope of these closures.

Contributor

quantoid commented Jun 6, 2013

Awesome, thanks! Where does the addShutdownHook come from? There seem to be so many classes mixed in to the scope of these closures.

@paoloambrosio

This comment has been minimized.

Show comment
Hide comment
@paoloambrosio

paoloambrosio Jun 6, 2013

Member

@quantoid No magic there, it's part of the Groovy Object API

Member

paoloambrosio commented Jun 6, 2013

@quantoid No magic there, it's part of the Groovy Object API

@quantoid

This comment has been minimized.

Show comment
Hide comment
@quantoid

quantoid Jun 6, 2013

Contributor

Hmm, IMHO would be better to tear stuff down as part of the feature execution block rather than when the JVM shuts down.

Contributor

quantoid commented Jun 6, 2013

Hmm, IMHO would be better to tear stuff down as part of the feature execution block rather than when the JVM shuts down.

@TarekSaid

This comment has been minimized.

Show comment
Hide comment
@TarekSaid

TarekSaid Jul 19, 2013

Hi,

I'd like to create a test database then destroy it after all the tests are done. The static boolean works for the @before tag, creating my database only once.

But how would I drop the database only after all my tests are done?

Hi,

I'd like to create a test database then destroy it after all the tests are done. The static boolean works for the @before tag, creating my database only once.

But how would I drop the database only after all my tests are done?

@aslakhellesoy

This comment has been minimized.

Show comment
Hide comment
@aslakhellesoy

aslakhellesoy Jul 19, 2013

Contributor

@TarekSaid this is a bug tracker, not a support forum. Please ask on the cukes google group. See https://github.com/cucumber/cucumber-jvm/blob/master/CONTRIBUTING.md

Contributor

aslakhellesoy commented Jul 19, 2013

@TarekSaid this is a bug tracker, not a support forum. Please ask on the cukes google group. See https://github.com/cucumber/cucumber-jvm/blob/master/CONTRIBUTING.md

@tschmal

This comment has been minimized.

Show comment
Hide comment
@tschmal

tschmal Aug 1, 2013

This will work OK for as completely global before/after, but it doesn't work if you want the behavior per feature file. For example, I may have 5 different feature files, each one having 10 different scenarios. Per feature, I may want a before/after. This workaround isn't per feature, but is per EVERYTHING. A per feature before/after would be nice.

For example, JBehave has a @Before/AfterStories. The code discussed in this thread would be equivalent to that, so this annotation isn't really necessary. It also has @Before/AfterScenario, which is equivalent to Cucumber's @Before/After. However, JBehave also has a @Before/AfterStory (singular) which isn't really doable with Cucumber-JVM (that I can tell). This would be very useful.

If you think about it, JUnit has it, too, with @Before/AfterClass.

Maybe I'm blind and there is a way to do it in Cucumber... but I can't see it.

tschmal commented Aug 1, 2013

This will work OK for as completely global before/after, but it doesn't work if you want the behavior per feature file. For example, I may have 5 different feature files, each one having 10 different scenarios. Per feature, I may want a before/after. This workaround isn't per feature, but is per EVERYTHING. A per feature before/after would be nice.

For example, JBehave has a @Before/AfterStories. The code discussed in this thread would be equivalent to that, so this annotation isn't really necessary. It also has @Before/AfterScenario, which is equivalent to Cucumber's @Before/After. However, JBehave also has a @Before/AfterStory (singular) which isn't really doable with Cucumber-JVM (that I can tell). This would be very useful.

If you think about it, JUnit has it, too, with @Before/AfterClass.

Maybe I'm blind and there is a way to do it in Cucumber... but I can't see it.

@paoloambrosio

This comment has been minimized.

Show comment
Hide comment
@paoloambrosio

paoloambrosio Aug 2, 2013

Member

@tschmal before/after feature hooks are out of the scope of this issue. They were discussed several times on The Cukes Google Group, so you might search there. In a recent thread I explained how to deal with feature tags. If you still think you need it, please write on the list first and explain your problem.

Member

paoloambrosio commented Aug 2, 2013

@tschmal before/after feature hooks are out of the scope of this issue. They were discussed several times on The Cukes Google Group, so you might search there. In a recent thread I explained how to deal with feature tags. If you still think you need it, please write on the list first and explain your problem.

@wjpowell

This comment has been minimized.

Show comment
Hide comment
@wjpowell

wjpowell Aug 3, 2013

Contributor

You don't need to do this in cucumber. Use the @BeforeClass and @afterclass annotation from within the JUnit test used to run the cucumber tests. This has the benefit of running only for the features specified by the paths or tags options.

@RunWith(Cucumber.class)
@Cucumber.Options(format = {"html:target/cucumber-html-report", "json-pretty:target/cucumber-json-report.json"})
public class RunCukesTest {

    @BeforeClass
    public static void setup() {
        System.out.println("Ran the before");
    }

    @AfterClass
    public static void teardown() {
        System.out.println("Ran the after");
    }
}
Contributor

wjpowell commented Aug 3, 2013

You don't need to do this in cucumber. Use the @BeforeClass and @afterclass annotation from within the JUnit test used to run the cucumber tests. This has the benefit of running only for the features specified by the paths or tags options.

@RunWith(Cucumber.class)
@Cucumber.Options(format = {"html:target/cucumber-html-report", "json-pretty:target/cucumber-json-report.json"})
public class RunCukesTest {

    @BeforeClass
    public static void setup() {
        System.out.println("Ran the before");
    }

    @AfterClass
    public static void teardown() {
        System.out.println("Ran the after");
    }
}
@aslakhellesoy

This comment has been minimized.

Show comment
Hide comment
@aslakhellesoy

aslakhellesoy Aug 3, 2013

Contributor

@wjpowell there is nothing in the Cucumber runner that handles @BeforeClass/@afterclass. Have you actually tried this?

Contributor

aslakhellesoy commented Aug 3, 2013

@wjpowell there is nothing in the Cucumber runner that handles @BeforeClass/@afterclass. Have you actually tried this?

@wjpowell

This comment has been minimized.

Show comment
Hide comment
@wjpowell

wjpowell Aug 3, 2013

Contributor

@aslakhellesoy I've tried it, and it works. The Cucumber runner calls super.run which handles the @BeforeClass and @afterclass annotated methods, as well as any @ClassRule defined.

Contributor

wjpowell commented Aug 3, 2013

@aslakhellesoy I've tried it, and it works. The Cucumber runner calls super.run which handles the @BeforeClass and @afterclass annotated methods, as well as any @ClassRule defined.

@aslakhellesoy

This comment has been minimized.

Show comment
Hide comment
@aslakhellesoy

aslakhellesoy Aug 3, 2013

Contributor

Thanks for the clarification. I thought it might be something like that.

Contributor

aslakhellesoy commented Aug 3, 2013

Thanks for the clarification. I thought it might be something like that.

@andryutz10

This comment has been minimized.

Show comment
Hide comment
@andryutz10

andryutz10 Feb 24, 2014

Contributor

Pull request created for this issue: #672
Just waiting for someone to take a look and approve it if its all good.

Contributor

andryutz10 commented Feb 24, 2014

Pull request created for this issue: #672
Just waiting for someone to take a look and approve it if its all good.

@alisterscott

This comment has been minimized.

Show comment
Hide comment
@alisterscott

alisterscott Feb 28, 2014

Would love to see this included in the latest version :)

Would love to see this included in the latest version :)

@mattwynne

This comment has been minimized.

Show comment
Hide comment
@mattwynne

mattwynne Mar 5, 2014

Member

I just used the BeforeClass and AfterClass annotations today and they worked perfectly. I'm not sure why we need to add our own BeforeAll / AfterAll hooks.

Member

mattwynne commented Mar 5, 2014

I just used the BeforeClass and AfterClass annotations today and they worked perfectly. I'm not sure why we need to add our own BeforeAll / AfterAll hooks.

@andryutz10

This comment has been minimized.

Show comment
Hide comment
@andryutz10

andryutz10 Mar 5, 2014

Contributor

@mattwynne, I see a few reasons:

  1. @BeforeClass and @afterclass are not part of the cucumber and having them in the runner class as static has no benefit but has a few downsides (usually a DI container is used and some components are injected in stepdefs classes to be used for "setUp/initialization" - how do you get those in the runner class on static context?? plus polluting the runner class with test logic)
  2. when you want to select a feature in Intellij Idea and run it, the cli.Main class will be used and your methods from runner class with @BeforeClass and @afterclass will never run.
  3. I don't know how many of you had this problem but in the last two years I used cucumber a lot, and I can say that because of small things like the setUp/tearDown for cucumber tests, your code for tests will get messy and hard to maintain because of the static state. For an example cucumber test, yes you can use in the runner @BeforeClass and @afterclass just to say that works, but in real world projects is not the same, you'll encounter all kinds of issues and something like @BeforeAll and @afterall helps a lot. That's my opinion and I might be wrong, but that is way I created this PR.
Contributor

andryutz10 commented Mar 5, 2014

@mattwynne, I see a few reasons:

  1. @BeforeClass and @afterclass are not part of the cucumber and having them in the runner class as static has no benefit but has a few downsides (usually a DI container is used and some components are injected in stepdefs classes to be used for "setUp/initialization" - how do you get those in the runner class on static context?? plus polluting the runner class with test logic)
  2. when you want to select a feature in Intellij Idea and run it, the cli.Main class will be used and your methods from runner class with @BeforeClass and @afterclass will never run.
  3. I don't know how many of you had this problem but in the last two years I used cucumber a lot, and I can say that because of small things like the setUp/tearDown for cucumber tests, your code for tests will get messy and hard to maintain because of the static state. For an example cucumber test, yes you can use in the runner @BeforeClass and @afterclass just to say that works, but in real world projects is not the same, you'll encounter all kinds of issues and something like @BeforeAll and @afterall helps a lot. That's my opinion and I might be wrong, but that is way I created this PR.
@aslakhellesoy

This comment has been minimized.

Show comment
Hide comment
@aslakhellesoy

aslakhellesoy Mar 5, 2014

Contributor

@mattwynne Because those annotations are from JUnit and they only work when you use the JUnit Cucumber runner.

Many people use Cucumber-JVM with the command-line runner, without JUnit at all, and then this would not work.

Contributor

aslakhellesoy commented Mar 5, 2014

@mattwynne Because those annotations are from JUnit and they only work when you use the JUnit Cucumber runner.

Many people use Cucumber-JVM with the command-line runner, without JUnit at all, and then this would not work.

@mattwynne

This comment has been minimized.

Show comment
Hide comment
@mattwynne

mattwynne Mar 5, 2014

Member

Good points!

Member

mattwynne commented Mar 5, 2014

Good points!

@aslakhellesoy

This comment has been minimized.

Show comment
Hide comment
@aslakhellesoy

aslakhellesoy Jun 26, 2014

Contributor

I'm reopening this ticket since I realised that #678 will not work at all when there is DI involved. More details in that issue.

Contributor

aslakhellesoy commented Jun 26, 2014

I'm reopening this ticket since I realised that #678 will not work at all when there is DI involved. More details in that issue.

@eelessam

This comment has been minimized.

Show comment
Hide comment
@eelessam

eelessam Mar 6, 2015

Is anyone working on this at the moment?

eelessam commented Mar 6, 2015

Is anyone working on this at the moment?

@fernandomora

This comment has been minimized.

Show comment
Hide comment
@fernandomora

fernandomora Mar 6, 2015

It this feature in the roadmap in a near future?

I have found the need of this feature several times in different projects.
And neither addShutdownHook nor @afterclass covered my needs, since we execute tests from sbt, addShutdownHook is only executed on JVM shutdown, while this does not happen until sbt is explicitly closed and I don't want to executed our tests in a forked JVM.

It this feature in the roadmap in a near future?

I have found the need of this feature several times in different projects.
And neither addShutdownHook nor @afterclass covered my needs, since we execute tests from sbt, addShutdownHook is only executed on JVM shutdown, while this does not happen until sbt is explicitly closed and I don't want to executed our tests in a forked JVM.

@ovictor

This comment has been minimized.

Show comment
Hide comment
@ovictor

ovictor May 27, 2015

+1 for this feature. Is anyone working on it?

ovictor commented May 27, 2015

+1 for this feature. Is anyone working on it?

@markwinspear

This comment has been minimized.

Show comment
Hide comment
@markwinspear

markwinspear May 27, 2015

And another +1 from me. I can't use Junit @before and @after annotations with Cucumber which prevents me from using Cucumber with WebDriver using Page Object Model and executing tests in Saucelabs

And another +1 from me. I can't use Junit @before and @after annotations with Cucumber which prevents me from using Cucumber with WebDriver using Page Object Model and executing tests in Saucelabs

@rvowles

This comment has been minimized.

Show comment
Hide comment
@rvowles

rvowles Jun 9, 2017

I have found the easiest way to do this is to create a new cucumber "Backend" and then use buildWorld and disposeWorld methods to hook into.

rvowles commented Jun 9, 2017

I have found the easiest way to do this is to create a new cucumber "Backend" and then use buildWorld and disposeWorld methods to hook into.

@marinat

This comment has been minimized.

Show comment
Hide comment
@marinat

marinat Jun 9, 2017

@rvowles Could you share example code, please?

marinat commented Jun 9, 2017

@rvowles Could you share example code, please?

@mpkorstanje

This comment has been minimized.

Show comment
Hide comment
@mpkorstanje

mpkorstanje Jun 9, 2017

Contributor

Another example solution using JUnit with class rules.

@RunWith(Cucumber.class)
public class Some02IT {

    @ClassRule
    public static TestRule classRule = (base, description) -> new Statement() {
        @Override
        public void evaluate() throws Throwable {
            try{
                setupExpensiveFixtures();
                base.evaluate();    
            } finally {
                tearDownExpensiveFixtures();
            }
        }
    };
}
Contributor

mpkorstanje commented Jun 9, 2017

Another example solution using JUnit with class rules.

@RunWith(Cucumber.class)
public class Some02IT {

    @ClassRule
    public static TestRule classRule = (base, description) -> new Statement() {
        @Override
        public void evaluate() throws Throwable {
            try{
                setupExpensiveFixtures();
                base.evaluate();    
            } finally {
                tearDownExpensiveFixtures();
            }
        }
    };
}
@rvowles

This comment has been minimized.

Show comment
Hide comment
@rvowles

rvowles Jun 11, 2017

@marinat just create a class in the cucumber.runtime package (in your project) that implements the class "Backend" (from the same package). We implement our initialization in loadGlue and static cleanup (disposing of temporary AWS queues) in disposeWorld.

rvowles commented Jun 11, 2017

@marinat just create a class in the cucumber.runtime package (in your project) that implements the class "Backend" (from the same package). We implement our initialization in loadGlue and static cleanup (disposing of temporary AWS queues) in disposeWorld.

@k1ru

This comment has been minimized.

Show comment
Hide comment

k1ru commented Aug 8, 2017

+1

@cfreitas-ig

This comment has been minimized.

Show comment
Hide comment
@cfreitas-ig

cfreitas-ig Sep 1, 2017

+1
Still waiting.

+1
Still waiting.

@shnako

This comment has been minimized.

Show comment
Hide comment

shnako commented Oct 24, 2017

+1

@aslakhellesoy

This comment has been minimized.

Show comment
Hide comment
@aslakhellesoy

aslakhellesoy Oct 24, 2017

Contributor

I realise this has been open for a long while. Thanks everyone for the +1 comments.

One way to increase the likelihood of this happening is to give financial support to the volunteers who maintain Cucumber: https://opencollective.com/cucumber

Contributor

aslakhellesoy commented Oct 24, 2017

I realise this has been open for a long while. Thanks everyone for the +1 comments.

One way to increase the likelihood of this happening is to give financial support to the volunteers who maintain Cucumber: https://opencollective.com/cucumber

@rvowles

This comment has been minimized.

Show comment
Hide comment
@rvowles

rvowles Oct 25, 2017

I thought I posted an answer to this? We used it to load all of our configuration, initialize log4j properly, and close down temporary SQS queues. Our test lead documents our e2e/cucumber stuff here: http://connect.cd/2017/10/introduction-to-microservice-test-automation-with-cucumber-jvm-and-openapi/

class must be in cumber.runtime package as that is all it scans.

package cucumber.runtime;

import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.snippets.FunctionNameGenerator;
import gherkin.formatter.model.Step;

import java.util.List;

public class BeforeAfterHooks implements Backend {
	private Glue glue;
	private List<String> gluePaths;

	public BeforeAfterHooks(ResourceLoader resourceLoader) {
	}

	@Override
	public void loadGlue(Glue glue, List<String> gluePaths) {
		this.glue = glue;
		this.gluePaths = gluePaths;
		
		// do your before hooks here
	}

	@Override
	public void setUnreportedStepExecutor(UnreportedStepExecutor executor) {

	}

	@Override
	public void buildWorld() {

	}

	@Override
	public void disposeWorld() {
		// do your after hooks here
	}

	@Override
	public String getSnippet(Step step, FunctionNameGenerator functionNameGenerator) {
		return null;
	}
}

rvowles commented Oct 25, 2017

I thought I posted an answer to this? We used it to load all of our configuration, initialize log4j properly, and close down temporary SQS queues. Our test lead documents our e2e/cucumber stuff here: http://connect.cd/2017/10/introduction-to-microservice-test-automation-with-cucumber-jvm-and-openapi/

class must be in cumber.runtime package as that is all it scans.

package cucumber.runtime;

import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.snippets.FunctionNameGenerator;
import gherkin.formatter.model.Step;

import java.util.List;

public class BeforeAfterHooks implements Backend {
	private Glue glue;
	private List<String> gluePaths;

	public BeforeAfterHooks(ResourceLoader resourceLoader) {
	}

	@Override
	public void loadGlue(Glue glue, List<String> gluePaths) {
		this.glue = glue;
		this.gluePaths = gluePaths;
		
		// do your before hooks here
	}

	@Override
	public void setUnreportedStepExecutor(UnreportedStepExecutor executor) {

	}

	@Override
	public void buildWorld() {

	}

	@Override
	public void disposeWorld() {
		// do your after hooks here
	}

	@Override
	public String getSnippet(Step step, FunctionNameGenerator functionNameGenerator) {
		return null;
	}
}
@nsidhaye

This comment has been minimized.

Show comment
Hide comment
@nsidhaye

nsidhaye Dec 21, 2017

I wanted to clenup some data after all scenarios from feature file. I believe @afterAll ("@tag") will be ultimate solution.

I tried with @After("@tag") but it gets executed after every scenario from feature file.

I wanted to clenup some data after all scenarios from feature file. I believe @afterAll ("@tag") will be ultimate solution.

I tried with @After("@tag") but it gets executed after every scenario from feature file.

@haroon-sheikh

This comment has been minimized.

Show comment
Hide comment
@haroon-sheikh

haroon-sheikh Dec 26, 2017

Contributor

@mpkorstanje Do you think we can progress #678 this now? This was reverted as it was failing on DI.

Contributor

haroon-sheikh commented Dec 26, 2017

@mpkorstanje Do you think we can progress #678 this now? This was reverted as it was failing on DI.

@mpkorstanje

This comment has been minimized.

Show comment
Hide comment
@mpkorstanje

mpkorstanje Dec 26, 2017

Contributor

I am not seeing a working pull request. And I have also not seen any fundamental discussion about how this is supposed to work with java8 and DI.

Contributor

mpkorstanje commented Dec 26, 2017

I am not seeing a working pull request. And I have also not seen any fundamental discussion about how this is supposed to work with java8 and DI.

@pkokoshnikov

This comment has been minimized.

Show comment
Hide comment
@pkokoshnikov

pkokoshnikov Dec 28, 2017

+1
it's really need for our testing. We use @BeforeClass @afterclass TestNG to prepare data on cloud service for group of tests. It's very expensive to create 'service project' for each scenario, thats why we want to use only one 'service project' for group of scenarios.

pkokoshnikov commented Dec 28, 2017

+1
it's really need for our testing. We use @BeforeClass @afterclass TestNG to prepare data on cloud service for group of tests. It's very expensive to create 'service project' for each scenario, thats why we want to use only one 'service project' for group of scenarios.

@ctang3

This comment has been minimized.

Show comment
Hide comment

ctang3 commented Jan 15, 2018

+1

@Silverrav

This comment has been minimized.

Show comment
Hide comment

+1

@Shurov

This comment has been minimized.

Show comment
Hide comment

Shurov commented Jan 24, 2018

+1

@599139

This comment has been minimized.

Show comment
Hide comment
@599139

599139 Jan 24, 2018

+1
In addition to@BeforeAll, can we have @BeforeFeature as well, something similar to Specflow? These hooks really makes framework maintenance easy.

Its really surprising to see this issue open since 2013!!

599139 commented Jan 24, 2018

+1
In addition to@BeforeAll, can we have @BeforeFeature as well, something similar to Specflow? These hooks really makes framework maintenance easy.

Its really surprising to see this issue open since 2013!!

@pgajeshwar-coupa

This comment has been minimized.

Show comment
Hide comment
@pgajeshwar-coupa

pgajeshwar-coupa Jan 30, 2018

+1
These are very basic hooks and must have in cucumber.

+1
These are very basic hooks and must have in cucumber.

@vikulin

This comment has been minimized.

Show comment
Hide comment

vikulin commented Feb 9, 2018

+1

@dhanainme

This comment has been minimized.

Show comment
Hide comment

+1

@symonk

This comment has been minimized.

Show comment
Hide comment
@symonk

symonk Mar 20, 2018

what is the best solution for runOnce on start / finish when running features in parallel on forked JVM processes?

symonk commented Mar 20, 2018

what is the best solution for runOnce on start / finish when running features in parallel on forked JVM processes?

@smsrede

This comment has been minimized.

Show comment
Hide comment
@smsrede

smsrede Apr 24, 2018

SOLUTION:
Tags are also used in Tagged Hooks, which let you use tags to define what Before and After
blocks get run for what scenarios. You can use this tag logic in your Hooks as well.

Exemple: 
Feature File:
=====================
.....
Feature: Test Tagged Hooks
@First
Scenario: This is First Scenario
	Given this is the first step
	When this is the second step
	Then this is the third step

@WhereEver
Scenario: This is xxxx Scenario
       Given this is the xxx step
        When this is the xxxx step
        Then this is the xxxxx step

======================
TestSteps Class:
======================
@Before("@First")
public void setUp(){
        ....WhereEver
        System.out.println("Before");
}

..........  The same to @After...........

    @After("@WhereEver")
    public void tearDown(){
        .....WhereEver
        System.out.println("After");
    }

Referências:
https://github.com/cucumber/cucumber/wiki/Tags
http://toolsqa.com/cucumber/tagged-hooks-in-cucumber/

Samuel Menezes, CTFL - Brasil/RJ

smsrede commented Apr 24, 2018

SOLUTION:
Tags are also used in Tagged Hooks, which let you use tags to define what Before and After
blocks get run for what scenarios. You can use this tag logic in your Hooks as well.

Exemple: 
Feature File:
=====================
.....
Feature: Test Tagged Hooks
@First
Scenario: This is First Scenario
	Given this is the first step
	When this is the second step
	Then this is the third step

@WhereEver
Scenario: This is xxxx Scenario
       Given this is the xxx step
        When this is the xxxx step
        Then this is the xxxxx step

======================
TestSteps Class:
======================
@Before("@First")
public void setUp(){
        ....WhereEver
        System.out.println("Before");
}

..........  The same to @After...........

    @After("@WhereEver")
    public void tearDown(){
        .....WhereEver
        System.out.println("After");
    }

Referências:
https://github.com/cucumber/cucumber/wiki/Tags
http://toolsqa.com/cucumber/tagged-hooks-in-cucumber/

Samuel Menezes, CTFL - Brasil/RJ
@scormaq

This comment has been minimized.

Show comment
Hide comment
@scormaq

scormaq May 11, 2018

Hi there,
I came to next solution, that does not require hooks or @BeforeClass/etc JUnit annotations, maybe it will be useful for someone. It is valid for Java8 + io.cucumber model and its reworked plugin approach:

  1. Create new plugin class by implementing cucumber.api.formatter.Formatter interface:
package com.foo.bar;

import cucumber.api.event.EventHandler;
import cucumber.api.event.EventPublisher;
import cucumber.api.event.TestRunFinished;
import cucumber.api.event.TestRunStarted;
import cucumber.api.formatter.Formatter;

public class Initialization implements Formatter {

    private EventHandler<TestRunStarted> setup = event -> {
        // setup static method(-s) here  
    };

    private EventHandler<TestRunFinished> teardown = event -> {
        // tear down static method(-s) here  
    };

    @Override
    public void setEventPublisher(EventPublisher publisher) {
        publisher.registerHandlerFor(TestRunStarted.class, setup);
        publisher.registerHandlerFor(TestRunFinished.class, teardown);
    }
}
  1. Apply this plugin to Cucumber main class, e.g. like in next example:
@RunWith(Cucumber.class)
@CucumberOptions(
        features = "src/test/resources/features/",
        glue = "com.foo.definitions",
        plugin = {"com.foo.bar.Initialization"})
public class CucumberRunner {
}

or via command line option like -Dcucumber.options="--plugin com.foo.bar.Initialization" etc.

P.S. In this way we are able to implement not only BeforeAll/AfterAll behavior, but also interceptors for very different Cucumber events (before/after features, scenarios, steps), full list here.

scormaq commented May 11, 2018

Hi there,
I came to next solution, that does not require hooks or @BeforeClass/etc JUnit annotations, maybe it will be useful for someone. It is valid for Java8 + io.cucumber model and its reworked plugin approach:

  1. Create new plugin class by implementing cucumber.api.formatter.Formatter interface:
package com.foo.bar;

import cucumber.api.event.EventHandler;
import cucumber.api.event.EventPublisher;
import cucumber.api.event.TestRunFinished;
import cucumber.api.event.TestRunStarted;
import cucumber.api.formatter.Formatter;

public class Initialization implements Formatter {

    private EventHandler<TestRunStarted> setup = event -> {
        // setup static method(-s) here  
    };

    private EventHandler<TestRunFinished> teardown = event -> {
        // tear down static method(-s) here  
    };

    @Override
    public void setEventPublisher(EventPublisher publisher) {
        publisher.registerHandlerFor(TestRunStarted.class, setup);
        publisher.registerHandlerFor(TestRunFinished.class, teardown);
    }
}
  1. Apply this plugin to Cucumber main class, e.g. like in next example:
@RunWith(Cucumber.class)
@CucumberOptions(
        features = "src/test/resources/features/",
        glue = "com.foo.definitions",
        plugin = {"com.foo.bar.Initialization"})
public class CucumberRunner {
}

or via command line option like -Dcucumber.options="--plugin com.foo.bar.Initialization" etc.

P.S. In this way we are able to implement not only BeforeAll/AfterAll behavior, but also interceptors for very different Cucumber events (before/after features, scenarios, steps), full list here.

@fspl001147

This comment has been minimized.

Show comment
Hide comment
@fspl001147

fspl001147 May 18, 2018

In Cucumber after last scenario the report is generated. I want to run few blocks of code after generation of report
(say : I want to compress the folder which contains report and mail it.
My question is as report is generated in the last of the program after last execution of last scenario and after class annotation. So where should I have to call that function which compress the report containing folder.)
Please suggest

In Cucumber after last scenario the report is generated. I want to run few blocks of code after generation of report
(say : I want to compress the folder which contains report and mail it.
My question is as report is generated in the last of the program after last execution of last scenario and after class annotation. So where should I have to call that function which compress the report containing folder.)
Please suggest

@mlvandijk

This comment has been minimized.

Show comment
Hide comment
@mlvandijk

mlvandijk May 18, 2018

Member

@fspl001147 For questions, please try one of our support options: https://cucumber.io/support

Member

mlvandijk commented May 18, 2018

@fspl001147 For questions, please try one of our support options: https://cucumber.io/support

@stale

This comment has been minimized.

Show comment
Hide comment
@stale

stale bot Jul 17, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in a week if no further activity occurs.

stale bot commented Jul 17, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in a week if no further activity occurs.

@stale stale bot added the Stale label Jul 17, 2018

@stale

This comment has been minimized.

Show comment
Hide comment
@stale

stale bot Jul 24, 2018

This issue has been automatically closed because of inactivity. You can support the Cucumber core team on opencollective.

stale bot commented Jul 24, 2018

This issue has been automatically closed because of inactivity. You can support the Cucumber core team on opencollective.

@stale stale bot closed this Jul 24, 2018

@haroon-sheikh

This comment has been minimized.

Show comment
Hide comment
@haroon-sheikh

haroon-sheikh Jul 24, 2018

Contributor

Re-opening the issue if someone fancies to submit a PR.

Contributor

haroon-sheikh commented Jul 24, 2018

Re-opening the issue if someone fancies to submit a PR.

@haroon-sheikh haroon-sheikh reopened this Jul 24, 2018

@stale stale bot removed the Stale label Jul 24, 2018

@michaelstanfa

This comment has been minimized.

Show comment
Hide comment
@michaelstanfa

michaelstanfa Jul 26, 2018

@fspl001147 did you find a solution to your issue? Also interested in similar functionality.

@fspl001147 did you find a solution to your issue? Also interested in similar functionality.

@ned29

This comment has been minimized.

Show comment
Hide comment
@ned29

ned29 Jul 27, 2018

Hi, I am also interested the solution, we have a lot of steps classes where we use an embedded mongo, so will be very useful to open connection once and close once

ned29 commented Jul 27, 2018

Hi, I am also interested the solution, we have a lot of steps classes where we use an embedded mongo, so will be very useful to open connection once and close once

@Abba-

This comment has been minimized.

Show comment
Hide comment
@Abba-

Abba- Jul 27, 2018

While I would like to see this with a simple tag, @rvowles solution has worked perfectly for me, just needed to be updated (see below). I needed to set System properties before running. I threw them in and it works for me.

This makes it work for me running a normal IDEA feature test (Right click -> run feature). I can't speak for @RunWith(cucumber.class).

Edited version as of July 2018 (Cucumber 2.4.0, Cucumber-Spring 2.3.0):

package cucumber.runtime; //cannot change.  can be under /test/java

import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.snippets.FunctionNameGenerator;
import gherkin.pickles.PickleStep;

import java.util.List;

public class WhateverYouWant implements Backend {
	private Glue glue;
	private List<String> gluePaths;

	public WhateverYouWant(ResourceLoader resourceLoader)  {  }

	@Override
	public void loadGlue(Glue glue, List<String> gluePaths) {
		this.glue = glue;
		this.gluePaths = gluePaths;
		
		// do your before hooks here
	}

        @Override
	public void disposeWorld() {
		// do your after hooks here
	}

	@Override
	public void setUnreportedStepExecutor(UnreportedStepExecutor executor) { }

	@Override
	public void buildWorld() { }

	@Override
	public String getSnippet(PickleStep pickleStep, String s, FunctionNameGenerator functionNameGenerator) {
		return null;
	}
}

Abba- commented Jul 27, 2018

While I would like to see this with a simple tag, @rvowles solution has worked perfectly for me, just needed to be updated (see below). I needed to set System properties before running. I threw them in and it works for me.

This makes it work for me running a normal IDEA feature test (Right click -> run feature). I can't speak for @RunWith(cucumber.class).

Edited version as of July 2018 (Cucumber 2.4.0, Cucumber-Spring 2.3.0):

package cucumber.runtime; //cannot change.  can be under /test/java

import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.snippets.FunctionNameGenerator;
import gherkin.pickles.PickleStep;

import java.util.List;

public class WhateverYouWant implements Backend {
	private Glue glue;
	private List<String> gluePaths;

	public WhateverYouWant(ResourceLoader resourceLoader)  {  }

	@Override
	public void loadGlue(Glue glue, List<String> gluePaths) {
		this.glue = glue;
		this.gluePaths = gluePaths;
		
		// do your before hooks here
	}

        @Override
	public void disposeWorld() {
		// do your after hooks here
	}

	@Override
	public void setUnreportedStepExecutor(UnreportedStepExecutor executor) { }

	@Override
	public void buildWorld() { }

	@Override
	public String getSnippet(PickleStep pickleStep, String s, FunctionNameGenerator functionNameGenerator) {
		return null;
	}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment