diff --git a/README.md b/README.md index 39e5892..cba1cfc 100644 --- a/README.md +++ b/README.md @@ -1 +1,259 @@ -# junit5-robolectric-extension \ No newline at end of file +# Junit5 Robolectric Extension (Experimental) + +This is an experimental project that aims to bridge the gap between JUnit 5 and Robolectric, providing a way to run your +Android unit tests using the modern JUnit 5 framework while leveraging Robolectric's +in-memory environment. + +## Key features + +* **JUnit 5 Compatibility:** Run your tests with the latest JUnit 5 features and syntax. + +## Current Limitations + +* **Parallel Execution:** Parallel test execution is not yet supported. We're actively working on addressing this + limitation in future releases. +* **ClassLoader:** Robolectric's classloader is set before launching the tests. Every test in the suite will use the + Robolectric's classloader, even if it is not annotated with the `RobolectricExtension`. +* **Experimental Status:** This extension is still under development, and its API might change in future versions. + +## Installation + +1. Add the Maven Central repository to your project's `build.gradle`: + +
+Kotlin + +```kotlin +repositories { + mavenCentral() +} +``` + +
+ +
+Groovy + +```groovy +repositories { + mavenCentral() +} +``` + +
+ +2. Enable JUnit Platform Launcher Interceptors and add the dependency to your app or library module's `build.gradle`: + +
+Kotlin + +```kotlin +android { + testOptions { + unitTests { + isIncludeAndroidResources = true + all { test -> + test.useJUnitPlatform() + test.jvmArgs(listOf("-Djunit.platform.launcher.interceptors.enabled=true")) + } + } + } +} + +dependencies { + testImplementation("tech.apter.junit.jupiter:robolectric-extension:0.1.0") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:") // JUnit 5 Jupiter Engine + // Optional dependencies if you want to use different version than used by the extension + testImplementation("org.junit.jupiter:junit-jupiter-api:") // Latest JUnit 5 Jupiter API + testImplementation("org.robolectric:robolectric:") // Latest Robolectric version +} +``` + +
+ +
+Groovy + +```groovy +android { + testOptions { + unitTests { + includeAndroidResources = true + all { + useJUnitPlatform() + jvmArgs('-Djunit.platform.launcher.interceptors.enabled=true') + } + } + } +} + +dependencies { + testImplementation 'tech.apter.junit.jupiter:robolectric-extension:0.1.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:' // Latest JUnit 5 Jupiter Engine + // Optional dependencies if you want to use different versions than used by the extension + testImplementation 'org.junit.jupiter:junit-jupiter-api:' // Latest JUnit 5 Jupiter API + testImplementation 'org.robolectric:robolectric:' // Latest Robolectric version +} +``` + +
+ +## Basic usage + +1. Annotate your test class with `@ExtendWith`. This extension will manage the Robolectric + environment for your tests: + +
+Kotlin + +```kotlin +@ExtendWith(RobolectricExtension::class) +``` + +
+ +
+Java + +```java +@ExtendWith(RobolectricExtension.class) +``` + +
+ +2. Utilize the standard JUnit 5 annotations (`@Test`, `@BeforeEach`, `@AfterEach`, etc.) within your test methods. You + could also use `org.jetbrains.kotlin:kotlin-test-junit5` package if you want to. + +
+Kotlin + +```kotlin + +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.AfterEach +import org.junit.jupiter.api.Assertions.assertInstanceOf +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.robolectric.annotation.Config +import tech.apter.junit.jupiter.robolectric.RobolectricExtension + +@ExtendWith(RobolectricExtension::class) +@Config(application = RobolectricExtensionSelfTest.MyTestApplication::class) +class RobolectricExtensionSelfTest { + + @BeforeEach + fun setUp() { + } + + @AfterEach + fun tearDown() { + } + + @Test + fun shouldInitializeAndBindApplicationAndCallOnCreate() { + val application = ApplicationProvider.getApplicationContext() + assertInstanceOf(MyTestApplication::class.java, application) + assertTrue((application as MyTestApplication).onCreateWasCalled) + } + + companion object { + @BeforeAll + @JvmStatic + fun setUpClass() { + } + + @AfterAll + @JvmStatic + fun tearDownClass() { + } + } + + class MyTestApplication : Application() { + internal var onCreateWasCalled = false + + override fun onCreate() { + this.onCreateWasCalled = true + } + } +} + +``` + +
+ +
+Java + +```java + +import android.app.Application; +import androidx.test.core.app.ApplicationProvider; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions.assertInstanceOf; +import org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.robolectric.annotation.Config; +import tech.apter.junit.jupiter.robolectric.RobolectricExtension; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(RobolectricExtension.class) +@Config(application = RobolectricExtensionSelfTest.MyTestApplication::class) +public class RobolectricExtensionSelfTest { + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void tearDown() { + } + + @Test + public void shouldInitializeAndBindApplicationAndCallOnCreate() { + final Application application = ApplicationProvider.getApplicationContext(); + assertInstanceOf(MyTestApplication.class, application); + assertTrue(((MyTestApplication) application).onCreateWasCalled); + } + + @BeforeAll + public static void setUpClass() { + } + + @AfterAll + public static void tearDownClass() { + } + + static class MyTestApplication extends Application { + public boolean onCreateWasCalled = false; + + @Override + public void onCreate() { + this.onCreateWasCalled = true; + } + } +} + +``` + +
+ +## Important Notes + +* Ensure `isIncludeAndroidResources` is set to true in your testOptions configuration to access Android resources for + your +* JUnit Platform Launcher Interceptors must be enabled (`junit.platform.launcher.interceptors.enabled=true`), otherwise + test instances will not be created by Robolectric's classloader. +* Parallel execution is currently not supported. Run tests sequentially for now. +