OSGi, JUnit 5 and @TestInstance

Hi,

I haev recently discovered that JUnit 5 allow you to control whether or not it reuses an instance of a test class for all tests, or creates a new instance for each test. However, the org.osgi:org.osgi.test.junit5 extension artifact doesn’t appear to support @TestInstance :cry:.

This test class works:

package com.example.stuff.testing

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.osgi.framework.Bundle
import org.osgi.framework.BundleContext
import org.osgi.service.component.annotations.RequireServiceComponentRuntime
import org.osgi.test.common.annotation.InjectBundleContext
import org.osgi.test.junit5.context.BundleContextExtension

@ExtendWith(value = [ BundleContextExtension::class ])
@RequireServiceComponentRuntime
class WorkingTest {
    companion object {
        @InjectBundleContext
        lateinit var bundleContext: BundleContext

        private lateinit var testBundle: Bundle

        @Suppress("unused")
        @BeforeAll
        @JvmStatic
        fun setup() {
            testBundle = bundleContext.bundle
        }
    }

    @Test
    fun myTest() {
        assertEquals("testing", testBundle.symbolicName)
    }
}

whereas this one does not:

package com.example.stuff.testing

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS
import org.junit.jupiter.api.extension.ExtendWith
import org.osgi.framework.Bundle
import org.osgi.framework.BundleContext
import org.osgi.service.component.annotations.RequireServiceComponentRuntime
import org.osgi.test.common.annotation.InjectBundleContext
import org.osgi.test.junit5.context.BundleContextExtension

@ExtendWith(value = [ BundleContextExtension::class ])
@RequireServiceComponentRuntime
@TestInstance(PER_CLASS)
class NotWorkingTest {
    @InjectBundleContext
    lateinit var bundleContext: BundleContext

    private lateinit var testBundle: Bundle

    @BeforeAll
    fun setup() {
        testBundle = bundleContext.bundle
    }

    @Test
    fun myTest() {
        assertEquals("testing", testBundle.symbolicName)
    }
}

The exception in the error case is:

# Execution Finished: NotWorkingTest - [engine:bnd-bundle-engine]/[bundle:testing;1.0.0.SNAPSHOT]/[sub-engine:junit-jupiter]/[class:com.example.stuff.testing.NotWorkingTest] - TestExecutionResult [status = FAILED, throwable = kotlin.UninitializedPropertyAccessException: lateinit property bundleContext has not been initialized]
kotlin.UninitializedPropertyAccessException: lateinit property bundleContext has not been initialized
        at com.example.stuff.testing.NotWorkingTest.setup(NotWorkingTest.kt:26)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        ...

which suggests that the injection would have happened in the @BeforeEach phase rather than the @BeforeAll phase.

@InjectService gives similar results.

The point of @TestInstance is that @BeforeAll/@AfterAll-scoped items no longer need to be static, and I suspect org.osgi.test.junit5 is not handling this case.

Cheers,
Chris

Without looking deeper into the cause, I’m not sure if this is related to bnd. This forum is a bit of a mixed bag between OSGi and bnd that is maintained by an overlapping heap of people, but I believe this is a case for the OSGi Test Project. → GitHub - osgi/osgi-test: Testing support for OSGi. Includes JUnit 4 and JUnit 5 support and AssertJ support.

Would you mind opening an issue there?

OK, raised as Issue #462.