- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 1.6k
Description
When writing a JUnit extension, I encountered problems when using the Junit Extension API that required me to change the applications in undesirable ways.
Code example below (heavily simplified) (Kotlin):
class Context {
  // thread local state
  fun executeWithSomeContext(action: Context -> Unit) =
    try {
       setup()
       action(context)
    } finally {
       cleanup()
    }
  
  internal fun setup() { } // < -- This had to be made non-internal for the extension
  internal fun cleanup() { } // < -- This had to be made non-internal for the extension
}The use of this class is to ensure clients always use the executeWithSomeContext to use the context, and cannot use the setup and cleanup methods.
We have built a JUnit extension that is used automatically set up this context for JUnit tests, using an annotation. The JUnit extension reads the annotation, sets up the correct context before the test, runs the test and clears the context.
Currently, the extension looks like
class ContextExtension : BeforeEach, AfterEach {
  val context = // ... 
  override fun beforeEach(...) {
    context.setup()
  }
  override fun afterEach(...) {
    context.cleanup()
  }
}Instead, it would be useful to be able to build the extension like
class ContextExtension : AroundEach {
  val context = // ... 
  override fun aroundEach(context: ExtensionContext, next: TestContinuation) {
    context.executeWithSomeContext(...) {
      next(context)
    }
  }
}To support this use case of the JUnit extension calling the Context setup/clear methods, they had to be made public and accessible outside the defining package. This allows other (user) code to circumvent the executeWithSomeContext method and call the setup or cleanup methods directly.
My use case is about setting up a context and automatically clearing it after the test, but this could be extended to other types of resources can be used, but not set up, stored or manually cleared by user code.
Even a common guide to JUnit extensions, https://www.baeldung.com/junit-5-extensions#3-lifecycle-callbacks, lists a database connection with a manual cleanup that could benefit from an Around* type extension, with a try/finally block to support correct cleaning up of resources.
Other languages and test frameworks have similar around extension APIs, for example around in RSpec (https://rubydoc.info/gems/rspec-core/RSpec%2FCore%2FHooks:around).
Another benefit of the Around* extension API is a clear stacktrace showing the call stack of each extension running around the actual JUnit test.
Some semantics that these interfaces should expose:
- The nextargument must be invoked exactly once by the extension.
- The name and type of the nextargument to thearoundEachmethod of theAroundEachinterface could be improved.
Deliverables
-  Addition of AroundAll,AroundEach,AroundTestinterfaces which will be handled in the test extension lifecycle by JUnit.
-  Optionally deprecate the Before*andAfter*, because they could be replaced by theAround*extension lifecycles.
Thanks in advance.