Skip to content
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

Allow @BeforeAll and @AfterAll methods to be non-static #419

Closed
14 tasks done
mfulton26 opened this issue Jul 22, 2016 · 41 comments
Closed
14 tasks done

Allow @BeforeAll and @AfterAll methods to be non-static #419

mfulton26 opened this issue Jul 22, 2016 · 41 comments

Comments

@mfulton26
Copy link

mfulton26 commented Jul 22, 2016

Overview

#88 explains why @BeforeAll and @AfterAll methods currently must be static; however, the question arises again and again.

Related Issues

Proposal

Reintroduce support for @TestInstance as was present in the JUnit 5 Prototype, thereby allowing developers and third party extension authors to make use of the feature as well. In other words, we do not want to limit use of this feature to JUnit Jupiter itself.

Open Issues

Special caution must be taken with regard to @Nested test classes in terms of the lifecycle of the test instance against which @BeforeAll and @AfterAll methods are executed.

Original Issue Description

Can support be added for @BeforeAll and @AfterAll methods in @Nested test classes?

For example:

class Tests {
    @Test
    void something() {
    }

    @BeforeAll(nested = SubTests.class)
    static void setUp() {
    }

    @Nested
    class SubTests {

        // ...

Deliverables

  • Reintroduce support for @TestInstance as was present in the JUnit 5 prototype.
    • Make @TestInstance an @Inherited annotation to support lifecycle inheritance semantics within a test class hierarchy.
  • Add support for @TestInstance for @Nested test classes.
    • Ensure proper behavior for @Nested test classes in terms of the lifecycle of the test instance against which @BeforeAll and @AfterAll methods are executed.
  • Allow @BeforeAll and @AfterAll methods to be non-static.
  • Move the getTestInstance() method from TestExtensionContext to ExtensionContext.
    • Ensure that the proper test instance is supplied to container-level extensions via the ExtensionContext.
    • Ensure that the proper test instance is supplied to TestInstancePostProcessor extensions via the ExtensionContext as well.
    • Ensure that the proper test instance is supplied to TestTemplateContainerExtensionContext extensions via the ExtensionContext as well.
  • Add documentation to the User Guide for the new features.
  • Update existing documentation in the User Guide which states that @BeforeAll and @AfterAll methods must be static.
  • Update existing JavaDoc which states that @BeforeAll and @AfterAll methods must be static.
  • Update the release notes in the User Guide describing the new features.
  • Update the release notes in the User Guide describing breaking changes.
@sbrannen
Copy link
Member

The short answer is "no".

For further details, see #48, #88, and especially this comment: #88 (comment).

However, I will leave this issue open since the question is asked so frequently on its own unrelated to scenario tests.

@sbrannen sbrannen changed the title BeforeAll/AfterAll for Nested Allow @BeforeAll and @AfterAll methods to be non-static Jul 22, 2016
@sbrannen
Copy link
Member

FYI: I have updated this issue's title and added an Overview section to its description.

@mfulton26
Copy link
Author

I see. Thanks!

@sdeleuze
Copy link

@sbrannen Allowing @BeforeAll and @AfterAll to be non-static would make usage of JUnit 5 much more pleasant with Kotlin where we currently have to use crappy code (even if you can blame Kotlin for that, but I believe they really did the best they could in finding a good tradeoff between good Java interrop and clean design) to make it work.

As described here, currently we have to create a companion object with method annotated with @JvmStatic to make it works.

Enabling that would allow Junit 5 usage much more simple, with idiomatic Kotlin code without requiring usage of a Kotlin specific library for testing.

@sbrannen
Copy link
Member

Hi @sdeleuze,

Nice to see a fellow core Spring committer chiming in here! 😉

As for your request... you're preaching to the choir (at least when addressing me). In the JUnit Lambda prototype @bechte and I implemented support for @BeforeAll and @AfterAll that only required such methods to be static if the test class was configured with "test instance per method" semantics.

I am personally totally in favor of bringing back that support. In fact, it is simply a requirement for proper support for Scenario Tests (see #48 for details). So it will have to be pulled back into the framework in one form or other, and that should happen in the M5 time frame.

On a different topic, what do you think about using Kotlin's spek testing framework? Is that a viable option for you? Or are you more focused on using the Spring TestContext Framework with JUnit Jupiter support for testing your Kotlin codebase?

@sbrannen
Copy link
Member

@junit-team/junit-lambda what do you guys think about reinstating the @TestInstance annotation for M4 since we'll need it (or something equivalent) for scenario tests in M5?

@sdeleuze
Copy link

My pleasure to be here :-)

I think both could make sense depending on the use case. For functional Spring + Kotlin applications like the one I develop on https://github.com/mix-it/mixit, I think Spek could be a better fit (we are going to use it shortly, it is on our TODO), while for regular Spring Boot annotation based applications, being able to take advantage of Spring TestContext Framework with JUnit Jupiter support would make sense for a lot of developers I think.

@sbrannen
Copy link
Member

Slated for M4 now in order to ease adoption for Kotlin users.

@sbrannen
Copy link
Member

Disclaimer: slated for M4, but might get shifted forward to M5 again. 😉

@sdeleuze
Copy link

That would be awesome in M4, but I notice the disclaimer ;-) Kotlin support is now one of the major themes of Spring Framework 5 as announced in my recent blog post and this issue is the only really annoying issue with Kotlin + Junit 5 I am aware of, so fingers crossed ;-)

@marcphilipp
Copy link
Member

what do you guys think about reinstating the @TestInstance annotation for M4 since we'll need it (or something equivalent) for scenario tests in M5?

I'm ok with reinstating it. We need to make sure to validate that test methods don't add instance level extensions like TestInstancePostProcessor then, though.

@sbrannen
Copy link
Member

I'm ok with reinstating it. We need to make sure to validate that test methods don't add instance level extensions like TestInstancePostProcessor then, though.

I'm not sure about that: sometimes you may want dependencies to be re-injected between test methods. So it's really up to the extension.

For example, with TestNG (which supports scenario-style tests), the Spring TestContext Framework re-injects dependencies if the previously executed test method was annotated with @DirtiesContext since the state of the previously injected dependencies is no longer valid.

@marcphilipp
Copy link
Member

Point taken.

@sbrannen
Copy link
Member

FYI: I have added Proposal and Open Issues sections to this issue's description.

@marcphilipp marcphilipp added this to the 5.0 M5 milestone Feb 22, 2017
sbrannen added a commit that referenced this issue Jun 30, 2017
sbrannen added a commit that referenced this issue Jun 30, 2017
sbrannen added a commit that referenced this issue Jun 30, 2017
sbrannen added a commit that referenced this issue Jun 30, 2017
sbrannen added a commit that referenced this issue Jun 30, 2017
sbrannen added a commit that referenced this issue Jun 30, 2017
sbrannen added a commit that referenced this issue Jun 30, 2017
sbrannen added a commit that referenced this issue Jun 30, 2017
Prior to this set of commits, the lifecycle for a test instance
followed per-method semantics, meaning that a new test instance was
created before the execution of each test, test factory, etc. This
behavior had a few drawbacks in certain scenarios. For example, it was
impossible to declare @BeforeAll and @afterall on non-static methods
since there was no cached instance against which those methods could be
invoked. It also made it more difficult to implement @BeforeAll and
@afterall methods in programming languages such as Kotlin.

This set of commits addresses these issues by reintroducing the
@testinstance annotation from the JUnit Lambda prototype.

@testinstance allows the test instance lifecycle to switched from the
default per-method mode to a new per-class mode simply by annotating
the test class with @testinstance(Lifecycle.PER_CLASS). This enables
shared test instance state between test methods in a given test class
as well as between non-static @BeforeAll and @afterall methods in a
test class.

Furthermore, since @BeforeAll and @afterall methods are no longer
required to be static (if the test class is annotated with
@testinstance(Lifecycle.PER_CLASS)), the following new use cases are
now supported.

- Declaration of @BeforeAll and @afterall methods in @nested test
  classes.
- Declaration of @BeforeAll and @afterall on interface default methods.
- Simplified declaration of @BeforeAll and @afterall methods in test
  classes implemented with the Kotlin programming language.

As a logical side effect of these changes, the getTestInstance() method
in the TestExtensionContext API has been moved to the ExtensionContext
API and now returns Optional<Object> instead of simply Object. This
makes it possible to access the test instance from container-level
extension APIs such as BeforeAllCallback and AfterAllCallback when
tests are executed using the per-class lifecycle mode.

Issue: #419
@sbrannen
Copy link
Member

This issue has been addressed in master in 502fc31.

@kcooney
Copy link
Member

kcooney commented Jul 29, 2017

Sorry to be late to the discussion. One option that I have considered in the past is to allow @BeforeAll methods take in a Store (the "class" Store). That Store could be used to store data needed for all test methods (like connection parameters to a locally created database, or the port of a locally running HTTP server). We could pass the same Store instances to any @AfterAll methods that take in a Store. A test method that takes in a Store would get a unique store for each test instance, but those stores would have their "parent" Srore being the one passed to the "class" Store

Since extensions have access to the Store already, this would allow for great reuse while still limiting accidental reuse of state between test instances.

(yes I realize for Kotlin we wouldn't want to require static methods; just suggesting a different solution for the general problem of scenario tests).

@sbrannen
Copy link
Member

Sorry to be late to the discussion.

Yesss... rather late to the closed discussion. 😉

If you'd like the team to consider your idea about sharing the Store with test code, please open a new issue.

Cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment