diff --git a/README.md b/README.md index 80a9786..da30160 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,15 @@ Declare a `Resources` in one of the three following ways, and register `Server` Get a `Resources` from: 1. A test method parameter injection, or -2. An instance variable, or -3. A static variable. +2. An instance field, or +3. A static field. The difference is in the lifecycle of the `Resources` object. For `#1`, a new instance is created for every test method. `#2` is the same as `#1` unless the test class declares `@TestInstance(TestInstance.Lifecycle.PER_CLASS)`, in which case one instance is shared among all the tests. `#3` is obviously one instance shared among all the tests. +Note that for `#2` and `#3`, if the variable is already been assigned a value by the user, the extension will not +reinitialize it. ``` @ExtendWith(GrpcCleanupExtension.class) diff --git a/gradle.properties b/gradle.properties index 6857123..8358839 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ ktlintVersion=9.3.0 bintrayPluginVersion=1.8.5 projectGroup=com.asarkar.grpc -projectVersion=1.0.0 +projectVersion=1.0.1 projectDescription=JUnit5 Extension that can automatically release gRPC resources at the end of the test licenseName=Apache-2.0 licenseUrl=http://www.apache.org/licenses/LICENSE-2.0.txt diff --git a/src/main/kotlin/com/asarkar/grpc/test/GrpcCleanupExtension.kt b/src/main/kotlin/com/asarkar/grpc/test/GrpcCleanupExtension.kt index 64e5b9a..6655176 100644 --- a/src/main/kotlin/com/asarkar/grpc/test/GrpcCleanupExtension.kt +++ b/src/main/kotlin/com/asarkar/grpc/test/GrpcCleanupExtension.kt @@ -40,6 +40,11 @@ class GrpcCleanupExtension : } if (shouldAccessResourcesField(ctx)) { + if (tryGet(ctx.requiredTestInstance) != null) { + throw PreconditionViolationException( + "Either set lifecycle PER_CLASS or don't initialize Resources field" + ) + } trySet(ctx.requiredTestInstance) } } @@ -58,6 +63,7 @@ class GrpcCleanupExtension : if (!successful) throw PostconditionViolationException("$resources and $it couldn't be released") else throw PostconditionViolationException("$it couldn't be released") } + trySet(ctx.requiredTestInstance, null) } } if (!successful) throw PostconditionViolationException("$resources couldn't be released") @@ -81,7 +87,9 @@ class GrpcCleanupExtension : throw JUnitException("Illegal state: Cannot access Resources field", e) } resourcesField = field - trySet(ctx.testInstance.orElse(null)) + if (tryGet(ctx.testInstance.orElse(null)) == null) { + trySet(ctx.testInstance.orElse(null)) + } } } @@ -98,9 +106,9 @@ class GrpcCleanupExtension : !resourcesField.isStatic() } - private fun trySet(target: Any?) { + private fun trySet(target: Any?, value: Resources? = Resources()) { try { - resourcesField?.takeIf { target != null || it.isStatic() }?.set(target, Resources()) + resourcesField?.takeIf { target != null || it.isStatic() }?.set(target, value) } catch (e: ReflectiveOperationException) { throw JUnitException("Illegal state: Cannot set Resources field", e) } diff --git a/src/test/kotlin/com/asarkar/grpc/test/ExampleTestCase2.kt b/src/test/kotlin/com/asarkar/grpc/test/ExampleTestCase2.kt index 8363d60..8c61f57 100644 --- a/src/test/kotlin/com/asarkar/grpc/test/ExampleTestCase2.kt +++ b/src/test/kotlin/com/asarkar/grpc/test/ExampleTestCase2.kt @@ -6,7 +6,7 @@ import org.mockito.Mockito @ExtendWith(GrpcCleanupExtension::class) class ExampleTestCase2 { - private var resources: Resources? = null + private lateinit var resources: Resources private val setOfResources: Set = mutableSetOf() private val set = Mockito.spy(setOfResources) diff --git a/src/test/kotlin/com/asarkar/grpc/test/ExampleTestCase3.kt b/src/test/kotlin/com/asarkar/grpc/test/ExampleTestCase3.kt index 17d1aa5..18026cc 100644 --- a/src/test/kotlin/com/asarkar/grpc/test/ExampleTestCase3.kt +++ b/src/test/kotlin/com/asarkar/grpc/test/ExampleTestCase3.kt @@ -21,9 +21,4 @@ class ExampleTestCase3 { fun test2() { setOfResources.plus(resources) } - - @Test - fun test3() { - setOfResources.plus(resources) - } } diff --git a/src/test/kotlin/com/asarkar/grpc/test/ExampleTestCase7.kt b/src/test/kotlin/com/asarkar/grpc/test/ExampleTestCase7.kt new file mode 100644 index 0000000..5601ddb --- /dev/null +++ b/src/test/kotlin/com/asarkar/grpc/test/ExampleTestCase7.kt @@ -0,0 +1,24 @@ +package com.asarkar.grpc.test + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.Mockito + +@ExtendWith(GrpcCleanupExtension::class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ExampleTestCase7 { + private var resources = Resources() + private val setOfResources: Set = mutableSetOf() + private val set = Mockito.spy(setOfResources) + + @Test + fun test1() { + setOfResources.plus(resources) + } + + @Test + fun test2() { + setOfResources.plus(resources) + } +} diff --git a/src/test/kotlin/com/asarkar/grpc/test/ExampleTestCase8.kt b/src/test/kotlin/com/asarkar/grpc/test/ExampleTestCase8.kt new file mode 100644 index 0000000..2896730 --- /dev/null +++ b/src/test/kotlin/com/asarkar/grpc/test/ExampleTestCase8.kt @@ -0,0 +1,13 @@ +package com.asarkar.grpc.test + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(GrpcCleanupExtension::class) +class ExampleTestCase8 { + private var resources = Resources() + + @Test + fun test() { + } +} diff --git a/src/test/kotlin/com/asarkar/grpc/test/GrpcCleanupExtensionIntegrationTests.kt b/src/test/kotlin/com/asarkar/grpc/test/GrpcCleanupExtensionIntegrationTests.kt index 16d444a..17a1572 100644 --- a/src/test/kotlin/com/asarkar/grpc/test/GrpcCleanupExtensionIntegrationTests.kt +++ b/src/test/kotlin/com/asarkar/grpc/test/GrpcCleanupExtensionIntegrationTests.kt @@ -187,7 +187,7 @@ class GrpcCleanupExtensionIntegrationTests { .testEvents() .assertThatEvents() .haveExactly( - 3, + 2, event(finishedSuccessfully()) ) @@ -269,4 +269,40 @@ class GrpcCleanupExtensionIntegrationTests { event(finishedWithFailure(instanceOf(PreconditionViolationException::class.java))) ) } + + @Test + fun testAlreadyInitialized() { + val mocks = mutableListOf() + val listener = MockCreationListener { mock, _ -> mocks.add(mock) } + Mockito.framework().addListener(listener) + EngineTestKit.engine("junit-jupiter") + .selectors( + selectClass(ExampleTestCase7::class.java) + ) + .execute() + .testEvents() + .assertThatEvents() + .haveExactly( + 2, + event(finishedSuccessfully()) + ) + + assertThat(mocks).allMatch { it is Set<*> } + assertThat(mocks.map { it as Set<*> }.toSet()).hasSize(1) + } + + @Test + fun testCannotRetainAlreadyInitialized() { + EngineTestKit.engine("junit-jupiter") + .selectors( + selectClass(ExampleTestCase8::class.java) + ) + .execute() + .testEvents() + .assertThatEvents() + .haveExactly( + 1, + event(finishedWithFailure(instanceOf(PreconditionViolationException::class.java))) + ) + } }