Skip to content

Commit

Permalink
test: Add test for repeated, test template and nested tests (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
warnyul authored Mar 19, 2024
1 parent c4b5a0d commit 5f4fcdd
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.RepeatedTest
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestFactory
import org.junit.jupiter.api.TestTemplate
import org.junit.runners.BlockJUnit4ClassRunner
import org.junit.runners.model.FrameworkMethod
import org.junit.runners.model.TestClass
import java.lang.reflect.Modifier
import java.util.Collections

private val parameterizedTestAnnotation: Class<out Annotation>? by lazy {
Expand All @@ -24,19 +28,35 @@ private val parameterizedTestAnnotation: Class<out Annotation>? by lazy {
}

internal fun BlockJUnit4ClassRunner.computeJUnit5TestMethods(): MutableList<FrameworkMethod> {
val testMethods = testClass.getAnnotatedMethods(Test::class.java)
val testFactoryMethods = testClass.getAnnotatedMethods(TestFactory::class.java)
val parameterizedTestMethods = if (parameterizedTestAnnotation == null) {
emptyList()
} else {
testClass.getAnnotatedMethods(parameterizedTestAnnotation)
fun testMethods(testClass: TestClass): MutableList<FrameworkMethod> {
val testMethods = testClass.getAnnotatedMethods(Test::class.java)
val testFactoryMethods = testClass.getAnnotatedMethods(TestFactory::class.java)
val repeatedTestMethods = testClass.getAnnotatedMethods(RepeatedTest::class.java)
val testTemplateMethods = testClass.getAnnotatedMethods(TestTemplate::class.java)
val parameterizedTestMethods = if (parameterizedTestAnnotation == null) {
emptyList()
} else {
testClass.getAnnotatedMethods(parameterizedTestAnnotation)
}

val nestedTestMethods = testClass
.javaClass
.declaredClasses
.filter { !Modifier.isStatic(it.modifiers) }
.map { testMethods(TestClass(it)) }
.flatten()

val methods = mutableListOf<FrameworkMethod>()
methods.addAll(testMethods)
methods.addAll(testTemplateMethods)
methods.addAll(testFactoryMethods)
methods.addAll(repeatedTestMethods)
methods.addAll(parameterizedTestMethods)
methods.addAll(nestedTestMethods)
return Collections.unmodifiableList(methods)
}

val methods = mutableListOf<FrameworkMethod>()
methods.addAll(testMethods)
methods.addAll(testFactoryMethods)
methods.addAll(parameterizedTestMethods)
return Collections.unmodifiableList(methods)
return testMethods(testClass)
}

@Suppress("UnusedReceiverParameter")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ internal class JUnit5RobolectricTestRunner(clazz: Class<*>, injector: Injector =

override fun computeTestMethods() = computeJUnit5TestMethods()

override fun validateNoNonStaticInnerClass(errors: MutableList<Throwable>) {
// Skip validation
}

override fun isIgnored(child: FrameworkMethod) = isJUnit5Ignored(child)

override fun validatePublicVoidNoArgMethods(
Expand All @@ -68,6 +72,10 @@ internal class JUnit5RobolectricTestRunner(clazz: Class<*>, injector: Injector =
RobolectricTestRunner.HelperTestRunner(bootstrappedTestClass) {
override fun computeTestMethods(): MutableList<FrameworkMethod> = computeJUnit5TestMethods()

override fun validateNoNonStaticInnerClass(errors: MutableList<Throwable>) {
// Skip validation
}

override fun isIgnored(child: FrameworkMethod) = isJUnit5Ignored(child)

override fun validatePublicVoidNoArgMethods(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package tech.apter.junit.jupiter.robolectric

import android.app.Application
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.extension.ExtendWith
import kotlin.test.Test
import kotlin.test.assertIs
import kotlin.test.assertNotNull

@ExtendWith(RobolectricExtension::class)
class RobolectricExtensionNestedSelfTest {
@Nested
inner class NestedSelfTest {
@Test
fun `Given a test extended with robolectric when call a nested test then robolectric should be available`() {
val application = assertDoesNotThrow { ApplicationProvider.getApplicationContext<Context>() }
assertNotNull(application)
assertIs<Application>(application, "application")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package tech.apter.junit.jupiter.robolectric

import android.app.Application
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.RepeatedTest
import org.junit.jupiter.api.RepetitionInfo
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.extension.ExtendWith
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertNotNull

@ExtendWith(RobolectricExtension::class)
class RobolectricExtensionRepeatedSelfTest {

@RepeatedTest(REPEATED_TEST_COUNT)
fun `Given a test extended with robolectric when call a repeated test then robolectric should be available`(
testInfo: RepetitionInfo,
) {
testCallCount++
val application = assertDoesNotThrow { ApplicationProvider.getApplicationContext<Context>() }
assertNotNull(application)
assertIs<Application>(application, "application")
assertEquals(REPEATED_TEST_COUNT, testInfo.totalRepetitions)
}

companion object {
private const val REPEATED_TEST_COUNT = 3
private var testCallCount: Int = 0

@AfterAll
@Throws(Exception::class)
@JvmStatic
fun `Repeated test should be called as much as REPEATED_TEST_COUNT`() {
assertEquals(REPEATED_TEST_COUNT, testCallCount)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package tech.apter.junit.jupiter.robolectric

import android.app.Application
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.TestTemplate
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.extension.ExtendWith
import org.junit.jupiter.api.extension.ExtensionContext
import org.junit.jupiter.api.extension.TestTemplateInvocationContext
import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider
import java.util.stream.Stream
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertNotNull

@ExtendWith(RobolectricExtension::class)
class RobolectricExtensionTestTemplateSelfTest {

@TestTemplate
@ExtendWith(RobolectricTestTemplateInvocationContextProvider::class)
fun `Given a test extended with robolectric when call a test template then robolectric should be available`() {
testCallCount++
val application = assertDoesNotThrow { ApplicationProvider.getApplicationContext<Context>() }
assertNotNull(application)
assertIs<Application>(application, "application")
}

companion object {
private var testCallCount: Int = 0

@AfterAll
@Throws(Exception::class)
@JvmStatic
fun `Test template should be called as much as defined RobolectricTestTemplateInvocationContextProvider`() {
assertEquals(2, testCallCount)
}
}
}

private fun noOpTestTemplateInvocationContext(): TestTemplateInvocationContext =
object : TestTemplateInvocationContext {}

private class RobolectricTestTemplateInvocationContextProvider : TestTemplateInvocationContextProvider {
override fun supportsTestTemplate(context: ExtensionContext): Boolean = true

override fun provideTestTemplateInvocationContexts(context: ExtensionContext): Stream<TestTemplateInvocationContext> {
return Stream.of(noOpTestTemplateInvocationContext(), noOpTestTemplateInvocationContext())
}
}

0 comments on commit 5f4fcdd

Please sign in to comment.