docs icon indicating copy to clipboard operation
docs copied to clipboard

[Kotlin] @BeforeAll and @AfterAll throws exceptions when used in kotlin

Open ocherniavskyi-lohika-tix opened this issue 3 years ago • 9 comments

Describe the bug @BeforeAll and @AfterAll throws exceptions when used in kotlin

To Reproduce

class MyStepDefinitions  {

    companion object {

        @JvmStatic
        @BeforeAll
        fun beforeAll() {
            println("before all")
        }

        @JvmStatic
        @AfterAll
        fun afterAll() {
            println("after all")
        }
    }

    //some steps declaration

Throws exception:


Before All/After All failed
io.cucumber.core.exception.CompositeCucumberException: There were 2 exceptions. The details are in the stacktrace below.
	at io.cucumber.core.runtime.RethrowingThrowableCollector.getThrowable(RethrowingThrowableCollector.java:57)
	at io.cucumber.core.runtime.CucumberExecutionContext.getThrowable(CucumberExecutionContext.java:81)
	at io.cucumber.core.runtime.CucumberExecutionContext.finishTestRun(CucumberExecutionContext.java:76)
	at io.cucumber.core.runtime.Runtime.execute(Runtime.java:94)
	at io.cucumber.core.runtime.Runtime.run(Runtime.java:85)
	at io.cucumber.core.cli.Main.run(Main.java:87)
	at io.cucumber.core.cli.Main.main(Main.java:30)
	Suppressed: io.cucumber.java.InvalidMethodSignatureException: A method annotated with BeforeAll or AfterAll must have one of these signatures:
 * public static void before_or_after_all()
at void com.lohika.cucumber.MyStepDefinitionsMethod$Companion.beforeAll()


		at io.cucumber.java.InvalidMethodSignatureException$InvalidMethodSignatureExceptionBuilder.build(InvalidMethodSignatureException.java:52)
		at io.cucumber.java.JavaStaticHookDefinition.createInvalidSignatureException(JavaStaticHookDefinition.java:44)
		at io.cucumber.java.JavaStaticHookDefinition.requireValidMethod(JavaStaticHookDefinition.java:28)
		at io.cucumber.java.JavaStaticHookDefinition.<init>(JavaStaticHookDefinition.java:17)
		at io.cucumber.java.GlueAdaptor.addDefinition(GlueAdaptor.java:30)
		at io.cucumber.java.JavaBackend.lambda$loadGlue$1(JavaBackend.java:42)
		at io.cucumber.java.MethodScanner.scan(MethodScanner.java:67)
		at io.cucumber.java.MethodScanner.scan(MethodScanner.java:58)
		at io.cucumber.java.MethodScanner.scan(MethodScanner.java:33)
		at io.cucumber.java.JavaBackend.lambda$loadGlue$2(JavaBackend.java:40)
		at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
		at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
		at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
		at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:274)
		at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
		at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
		at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
		at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
		at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
		at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
		at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
		at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
		at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
		at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
		at io.cucumber.java.JavaBackend.loadGlue(JavaBackend.java:40)
		at io.cucumber.core.runner.Runner.<init>(Runner.java:56)
		at io.cucumber.core.runtime.SingletonRunnerSupplier.createRunner(SingletonRunnerSupplier.java:44)
		at io.cucumber.core.runtime.SingletonRunnerSupplier.get(SingletonRunnerSupplier.java:35)
		at io.cucumber.core.runtime.RethrowingThrowableCollector.executeAndThrow(RethrowingThrowableCollector.java:35)
		at io.cucumber.core.runtime.CucumberExecutionContext.getRunner(CucumberExecutionContext.java:114)
		at io.cucumber.core.runtime.CucumberExecutionContext.runBeforeAllHooks(CucumberExecutionContext.java:65)
		at io.cucumber.core.runtime.Runtime.lambda$run$0(Runtime.java:81)
		at io.cucumber.core.runtime.Runtime.execute(Runtime.java:94)
		at io.cucumber.core.runtime.Runtime.run(Runtime.java:80)
		... 2 more
	Suppressed: io.cucumber.java.InvalidMethodSignatureException: A method annotated with BeforeAll or AfterAll must have one of these signatures:
 * public static void before_or_after_all()
at void com.lohika.cucumber.MyStepDefinitionsMethod$Companion.beforeAll()


		at io.cucumber.java.InvalidMethodSignatureException$InvalidMethodSignatureExceptionBuilder.build(InvalidMethodSignatureException.java:52)
		at io.cucumber.java.JavaStaticHookDefinition.createInvalidSignatureException(JavaStaticHookDefinition.java:44)
		at io.cucumber.java.JavaStaticHookDefinition.requireValidMethod(JavaStaticHookDefinition.java:28)
		at io.cucumber.java.JavaStaticHookDefinition.<init>(JavaStaticHookDefinition.java:17)
		at io.cucumber.java.GlueAdaptor.addDefinition(GlueAdaptor.java:30)
		at io.cucumber.java.JavaBackend.lambda$loadGlue$1(JavaBackend.java:42)
		at io.cucumber.java.MethodScanner.scan(MethodScanner.java:67)
		at io.cucumber.java.MethodScanner.scan(MethodScanner.java:58)
		at io.cucumber.java.MethodScanner.scan(MethodScanner.java:33)
		at io.cucumber.java.JavaBackend.lambda$loadGlue$2(JavaBackend.java:40)
		at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
		at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
		at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
		at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:274)
		at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
		at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
		at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
		at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
		at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
		at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
		at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
		at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
		at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
		at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
		at io.cucumber.java.JavaBackend.loadGlue(JavaBackend.java:40)
		at io.cucumber.core.runner.Runner.<init>(Runner.java:56)
		at io.cucumber.core.runtime.SingletonRunnerSupplier.createRunner(SingletonRunnerSupplier.java:44)
		at io.cucumber.core.runtime.SingletonRunnerSupplier.get(SingletonRunnerSupplier.java:35)
		at io.cucumber.core.runtime.RethrowingThrowableCollector.executeAndThrow(RethrowingThrowableCollector.java:35)
		at io.cucumber.core.runtime.CucumberExecutionContext.getRunner(CucumberExecutionContext.java:114)
		at io.cucumber.core.runtime.CucumberExecutionContext.runAfterAllHooks(CucumberExecutionContext.java:70)
		at io.cucumber.core.runtime.Runtime.execute(Runtime.java:94)
		at io.cucumber.core.runtime.Runtime.run(Runtime.java:84)
		... 2 more

Your Environment

  • Versions used 7.1.0

You have to use package level functions. For example:

package io.cucumber.example

import io.cucumber.java.AfterAll
import io.cucumber.java.BeforeAll

@BeforeAll
fun beforeAll() {
    println("before all")
}

@AfterAll
fun afterAll() {
    println("after all")
}

When using a companion object, Kotlin will create an class MyStepDefinitionsMethod$Companion which has non-static methods. The @JvmStatic annotation does not prevent this, it only adds the static methods to MyStepDefinitionsMethod.As a result Cucumber will detect both the static method ons MyStepDefinitions as well as the non-static methods on MyStepDefinitions$Companion and complain about the second one.

mpkorstanje avatar Nov 30 '21 22:11 mpkorstanje

@mpkorstanje thanks a lot, could you be added to docs?

They're kept here, feel free to send a pull request.

https://github.com/cucumber/docs

mpkorstanje avatar Dec 01 '21 16:12 mpkorstanje

@mpkorstanje & @mlvandijk I can add this info to the doc. Which section of the doc would you like to add it to? May I propose to add it to https://cucumber.io/docs/guides/10-minute-tutorial/ as a note? Please let me know what you think and assign this issue to me :)

10xtechie avatar Jun 15 '22 13:06 10xtechie

https://docs.cucumber.io/docs/cucumber/api/

Under "Hooks".

mpkorstanje avatar Jun 15 '22 13:06 mpkorstanje

@mpkorstanje, Thanks for your suggestion and assigning it to me! I am thinking of place it under the tip of which heading reads Think twice before you use Before (see screenshot below), but it will be shown as warning not as tip. Please let me know what you think.

hook-doc

Also, I have noticed that there is a Hugo partial layout named warn.html, but that uses message is-danger css classes instead of message is-warning. Can I change warn.html to use message is-warning and create a new Hugo partial payout for danger, naming danger.html and using message is-danger css classes?

10xtechie avatar Jun 16 '22 14:06 10xtechie

I wouldn't know how to answer that one. I'm not that deep into the docs project. Might be best to stick with what there is for this PR and sort out the danger/warn difference on a separate issue.

mpkorstanje avatar Jun 16 '22 21:06 mpkorstanje

Also, I have noticed that there is a Hugo partial layout named warn.html, but that uses message is-danger css classes instead of message is-warning. Can I change warn.html to use message is-warning and create a new Hugo partial payout for danger, naming danger.html and using message is-danger css classes?

I would say, let's do it. Just: do we use that partial in the doc? That would help to check if we break something or not.

aurelien-reeves avatar Jun 17 '22 07:06 aurelien-reeves

Also, I have noticed that there is a Hugo partial layout named warn.html, but that uses message is-danger css classes instead of message is-warning. Can I change warn.html to use message is-warning and create a new Hugo partial payout for danger, naming danger.html and using message is-danger css classes?

I would say, let's do it. Just: do we use that partial in the doc? That would help to check if we break something or not.

@aurelien-reeves , Yes, we use the partial named warn.html in step-definitions.md at line #193. You can see it live at https://cucumber.io/docs/cucumber/step-definitions/ but you'll have click javascript tab. Thanks for your suggestion I will fix this but creating a separate issue for easy reference

10xtechie avatar Jun 17 '22 17:06 10xtechie

Looks like the original issue has been fixed. Can this issue be closed?

mlvandijk avatar Jul 02 '23 04:07 mlvandijk