-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Extensions for AroundAll
, AroundEach
and AroundTest
#3221
Comments
@hiddewie This sounds a lot like Alternatively, I recently authored a resources extension for junit-pioneer which sounds like it does something similar to what you want. I hope this helps. |
@jbduncan Thanks for the suggestion. I tried the @ExtendWith(ContextExtension::class, ContextInterceptor::class)
class ContextTest {
companion object {
@BeforeAll
@JvmStatic
fun ba() {
println("in before all")
}
}
@Test
fun test() {
println("running test")
}
}
class ContextExtension : BeforeAllCallback {
override fun beforeAll(context: ExtensionContext?) {
println("Before all execution")
}
}
class ContextInterceptor : InvocationInterceptor {
override fun interceptBeforeAllMethod(invocation: InvocationInterceptor.Invocation<Void>, invocationContext: ReflectiveInvocationContext<Method>?, extensionContext: ExtensionContext?) {
println("before all proceed")
invocation.proceed()
println("after all proceed")
}
} This wraps the The code prints
But I require something like
irrespective if there are zero, one or multiple Using the I did find some historical issues/PRs with similar requests:
Especially #1442 seems similar to this issue.
Interesting. This will unfortunately not work for my use case with thread locals as 'resources' that need to be kept internal and have no create/get/set access outside the package. But for most other types of 'external' resources it would probably work nicely. |
@hiddewie Oh, I see, thanks for clarifying! Indeed, intercepting just the Have you tried overriding Otherwise, I think |
@hiddewie I don't suppose you've found the time to try |
@hiddewie For setting up a resource and clearing it, there's |
Yes I have tried I made another fake test to explain my thinking: @ExtendWith(ContextExtension::class, ContextInterceptor::class)
class ContextTest {
@Test fun test1() = println("running test 1")
@Test fun test2() = println("running test 2")
@Test fun test3() = println("running test 3")
}
class ContextExtension : BeforeAllCallback, AfterAllCallback {
override fun beforeAll(context: ExtensionContext?) {
println("Before all execution")
}
override fun afterAll(context: ExtensionContext?) {
println("After all execution")
}
}
class Context {
fun use(value: String, action: () -> Unit) =
try {
println("Setting context for $value")
action()
} finally {
println("Clearing context for $value")
}
}
class ContextInterceptor : InvocationInterceptor {
override fun interceptTestMethod(invocation: InvocationInterceptor.Invocation<Void>, invocationContext: ReflectiveInvocationContext<Method>?, extensionContext: ExtensionContext?) {
Context().use("test-context") {
invocation.proceed()
}
}
} The output is
while I would need something like
(the order of the beforeAll/afterAll interceptors does not much matter, as long as it only runs once at the correct test stage) Thanks for the suggestion. Using a In the issue description, the setting and cleaning methods are the 2 context methods that I do not want to expose publicly. Only the |
To give my use case a bit more context. A similar Java API is proposed for the Scoped Variables, JEP 429, https://openjdk.org/jeps/429. var result = ScopedValue.where(Server.PRINCIPAL, guest)
.call { test.run() } The construct to manipulate The JEP reasons about the Java API:
(emphasis mine) |
@hiddewie Thanks for providing more detail! I agree that there's no way to do this with the current extension APIs. While JUnit 4's extension model works like that, we opted for more fine-granular but composable extension points.
Would it be possible to put the |
Thanks for the comment.
It might be possible, but I think this is discouraged and not conform the idea of one-package-belongs-to-one-module when using Jigsaw on the JVM 9+. When fully using modules, the classes in a package must all be part of the same module. I have to experiment a bit with my code to see how large a blocker it is to put test code in the same package as the infrastructure code. |
Team decision: For the reasons stated in #3221 (comment) we won't add support for "around" type of extensions. |
Thanks for looking into it, I understand your decision. |
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):
The use of this class is to ensure clients always use the
executeWithSomeContext
to use the context, and cannot use thesetup
andcleanup
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
Instead, it would be useful to be able to build the extension like
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 theexecuteWithSomeContext
method and call thesetup
orcleanup
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:
next
argument must be invoked exactly once by the extension.next
argument to thearoundEach
method of theAroundEach
interface could be improved.Deliverables
AroundAll
,AroundEach
,AroundTest
interfaces which will be handled in the test extension lifecycle by JUnit.Before*
andAfter*
, because they could be replaced by theAround*
extension lifecycles.Thanks in advance.
The text was updated successfully, but these errors were encountered: