Skip to content
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

test: Add test for repeated, test template and nested tests #21

Merged
merged 2 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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())
}
}
Loading