diff --git a/docs/roborazzi-docs.tree b/docs/roborazzi-docs.tree index 11e2edf89..1e810c25e 100644 --- a/docs/roborazzi-docs.tree +++ b/docs/roborazzi-docs.tree @@ -11,6 +11,7 @@ + \ No newline at end of file diff --git a/docs/topics/junit5.md b/docs/topics/junit5.md new file mode 100644 index 000000000..c66b28f85 --- /dev/null +++ b/docs/topics/junit5.md @@ -0,0 +1,87 @@ +# JUnit 5 support + +Roborazzi supports the execution of screenshot tests with JUnit 5, +powered by the combined forces of the [Android JUnit 5](https://github.com/mannodermaus/android-junit5) plugin +and the [JUnit 5 Robolectric Extension](https://github.com/apter-tech/junit5-robolectric-extension). + +### Setup + +To get started with Roborazzi for JUnit 5, make sure to set up your project for the new testing framework first +and add the dependencies for JUnit Jupiter and the Robolectric extension to your project (check the readme files +of either project linked above to find the latest version). Then, add the `roborazzi-junit5` dependency +next to the existing Roborazzi dependency. The complete build script setup looks something like this: + +```kotlin +// Root moduls's build.gradle.kts: +plugins { + id("io.github.takahirom.roborazzi") version "$roborazziVersion" apply false + id("de.mannodermaus.android-junit5") version "$androidJUnit5Version" apply false + id("tech.apter.junit5.jupiter.robolectric-extension-gradle-plugin") version "$robolectricExtensionVersion" apply false +} +``` + +```kotlin +// App module's build.gradle.kts: +plugins { + id("de.mannodermaus.android-junit5") + id("tech.apter.junit5.jupiter.robolectric-extension-gradle-plugin") +} + +dependencies { + testImplementation("org.robolectric:robolectric:$robolectricVersion") + testImplementation("io.github.takahirom.roborazzi:$roborazziVersion") + testImplementation("io.github.takahirom.roborazzi-junit5:$roborazziVersion") + + testImplementation("org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion") +} +``` + +You are now ready to write a JUnit 5 screenshot test with Roborazzi. + +### Write a test + +JUnit 5 does not have a concept of `@Rule`. Instead, extension points to the test framework have to be registered, +and Roborazzi is no exception to this. Add the `@ExtendWith` annotation to the test class and insert both the +extension for Robolectric (from the third-party dependency defined above) and Roborazzi (from `roborazzi-junit5`). +If you also have JUnit 4 on the classpath, make sure to import the correct `@Test` annotation (`org.junit.jupiter.api.Test` +instead of `org.junit.Test`): + +```kotlin +// MyTest.kt: +@ExtendWith(RobolectricExtension::class, RoborazziExtension::class) +class MyTest { + @Test + fun test() { + // Your ordinary Roborazzi setup here, for example: + ActivityScenario.launch(MainActivity::class.java) + onView(isRoot()).captureRoboImage() + } +} +``` + +### Automatic Extension Registration + +You may tell JUnit 5 to automatically attach the `RoborazziExtension` to applicable test classes, +minimizing the redundancy of having to add `@ExtendWith(RoborazziExtension::class)` to every class. +This is done via a process called [Automatic Extension Registration](https://junit.org/junit5/docs/current/user-guide/#extensions-registration-automatic) and must be enabled in the build file. +Be aware that you still need `ExtendWith` for the `RobolectricExtension`, since it is not eligible for +automatic registration. Think of it as the JUnit 5 equivalent of `@RunWith(RobolectricTestRunner::class)`: + +```kotlin +// App module's build.gradle.kts: +junitPlatform { + configurationParameter( + "junit.jupiter.extensions.autodetection.enabled", + "true" + ) +} +``` + +```kotlin +// MyTest.kt: +@ExtendWith(RobolectricExtension::class) +class MyTest { + // ... +} +``` diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 33158f33c..4c3fedba6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ mavenPublish = "0.25.3" composeCompiler = "1.5.6" composeMultiplatform = "1.6.2" junit5Android = "1.10.0.0" -junit5Robolectric = "0.5.2" +junit5Robolectric = "0.7.0" robolectric = "4.12.2" robolectric-android-all = "Q-robolectric-5415296" @@ -54,6 +54,9 @@ kotlin-stdlib-jdk8 = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test" } kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit" } +android-junit5-plugin = { module = "de.mannodermaus.gradle.plugins:android-junit5", version.ref = "junit5Android" } +robolectric-junit5-plugin = { module = "tech.apter.junit5.jupiter:robolectric-extension-gradle-plugin", version.ref = "junit5Robolectric" } + androidx-activity = { module = "androidx.activity:activity", version.ref = "androidx-activity" } androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" } androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" } diff --git a/include-build/roborazzi-gradle-plugin/build.gradle b/include-build/roborazzi-gradle-plugin/build.gradle index cb360dfea..ffc0fbbf0 100644 --- a/include-build/roborazzi-gradle-plugin/build.gradle +++ b/include-build/roborazzi-gradle-plugin/build.gradle @@ -22,6 +22,8 @@ dependencies { integrationTestDepImplementation libs.android.tools.build.gradle integrationTestDepImplementation libs.kotlin.gradle.plugin integrationTestDepImplementation libs.compose.gradle.plugin + integrationTestDepImplementation libs.android.junit5.plugin + integrationTestDepImplementation libs.robolectric.junit5.plugin } sourceSets {