JUnit 5 for Android testing

26k views Asked by At

How to configure JUnit 5 for Android unit testing? I tried:

testCompile("org.junit.jupiter:junit-jupiter-api:5.0.0")

But it doesn't work, when I run previous the simplest unit test:

@Test
public void addition_isCorrect() throws Exception {
    assertEquals(4, 2 + 2);
}

I get error:

Exception in thread "main" java.lang.NoSuchMethodError: org.junit.platform.commons.util.ReflectionUtils.getDefaultClassLoader()Ljava/lang/ClassLoader;
    at org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry.loadTestEngines(ServiceLoaderTestEngineRegistry.java:31)
    at org.junit.platform.launcher.core.LauncherFactory.create(LauncherFactory.java:42)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:36)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

Process finished with exit code 1
Empty test suite.
6

There are 6 answers

0
Sormuras On

Android Studio is based on IDEA, correct?

Then see this answer here https://stackoverflow.com/a/46161799/1431016 or read directly the user-guide at http://junit.org/junit5/docs/current/user-guide/#running-tests-ide-intellij-idea

Summary:

// Only needed to run tests in an IntelliJ IDEA that bundles an older version
testImplementation("org.junit.platform:junit-platform-launcher:1.0.0")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.0.0")
testImplementation("org.junit.vintage:junit-vintage-engine:4.12.0")

I didn't try this project yet, but it could help you using JUnit 5 on Android: https://github.com/aurae/android-junit5

0
WebViewer On

It is January 2023 and the answers here that used to work, do not work for me on Android Studio 2021.3.1 (Patch 1), running Gradle 7.4.

This is what I did to make mine work:

  1. First, attempted to follow the answer by @Mahozad. I chose it because it referred to the latest junit-jupiter:5.9.1 version.
  2. But my app's build.gradle did not like the plugins {...} section from there, so I used apply plugin: 'de.mannodermaus.android-junit5' instead, from @BoonKeatTeo's article.
  3. Still, it would not recognize any of the imported symbols and so I added the repository URL from @DagnogoJean-François's answer (File > Settings > Build... > Remote Jar Repositories)
  4. It continued complaining about an import static org.junit.jupiter.api.Assertions.*; added to Test class and after running from the command line gradlew build --warning-mode=all, I realized that it is a good idea to remove the deprecated jcenter repository. In addition to removing it via Settings, I replaced all jcenter() occurrences with mavenCentral() in the root build.gradle.
  5. I still had the import warning, so I decided to remove all imports and accept the suggestion by Android Studio to add a org.junit.jupiter:junit-jupiter:5.8.1 dependency. This seems to have done the magic and now there are no warnings on any of my Test class symbols.

To summarize, here is how my build.gradle looks now:

apply plugin: 'com.android.library'
apply plugin: 'de.mannodermaus.android-junit5'

android {
    compileSdkVersion 33
    buildToolsVersion "33.0.1"
    compileOptions.encoding = 'windows-1251'
    useLibrary 'org.apache.http.legacy'
    namespace 'com.susu.mylib'

    defaultConfig {
        minSdkVersion 26
        targetSdkVersion 33
    }

    buildTypes {
        release {
            minifyEnabled true
            proguardFiles 'proguard.cfg'
        }
    }

    testOptions {
        unitTests.all {
            useJUnitPlatform()
        }
    }
}

dependencies {
    implementation "androidx.core:core-ktx:1.9.0"
    implementation 'org.jbundle.util.osgi.wrapped:org.jbundle.util.osgi.wrapped.org.apache.http.client:4.1.2'
    implementation "com.android.billingclient:billing:5.1.0"

    implementation 'org.junit.jupiter:junit-jupiter:5.8.1'
}

Comments on how to improve this further are greatly appreciated.

0
Mahozad On

Refer to this issue and this issue regarding JUnit 5 support on Android.

Add this build script dependency in your top-level build.gradle[.kts] file:

buildscript {
  dependencies {
    classpath("de.mannodermaus.gradle.plugins:android-junit5:1.8.2.1")
  }
}

And add these lines in your app or library build.gradle[.kts] file:

plugins {
  // ...
  id("de.mannodermaus.android-junit5")
}

dependencies {
  // Aggregator dependency on JUnit api, engine, and params
  testImplementation("org.junit.jupiter:junit-jupiter:5.9.1")
  // (Optional) If you also have JUnit 4-based tests
  testImplementation("junit:junit:4.13.2")
  testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.9.1")
}

You can use the above solution if you are using Android Gradle plugin 3.2.0 or higher and Gradle 4.7 or higher. For more information refer to the plugin GitHub page.

Extended answer

If you want to use JUnit 5 in your instrumented tests (androidTest source set) do the following:

  1. Add these dependencies to your app or libray build script:
androidTestImplementation("de.mannodermaus.junit5:android-test-core:1.3.0")
androidTestRuntimeOnly("de.mannodermaus.junit5:android-test-runner:1.3.0")
  1. Use ActivityScenarioExtension instead of ActivityScenarioRule in your test classes:
import de.mannodermaus.junit5.ActivityScenarioExtension

class MyActivityTest {

  @JvmField
  @RegisterExtension
  val scenarioExtension = ActivityScenarioExtension.launch<MyActivity>()

  @Test
  fun test1() {
    val scenario = scenarioExtension.scenario
    scenario.moveToState(Lifecycle.State.RESUMED)
    assertThat(scenario.state).isEqualTo(Lifecycle.State.RESUMED)
  }

  @Test
  fun test2(scenario: ActivityScenario<MyActivity>) {
    scenario.moveToState(Lifecycle.State.RESUMED)
    assertThat(scenario.state).isEqualTo(Lifecycle.State.RESUMED)
  }
}
1
Dagnogo Jean-François On

USE ALWAYS THE OFFICIAL VERSION

First go to the official documentation of Junit here : https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api you will see all latest version like this enter image description here

then in your app/gradle add this dependencie :

testImplementation('org.junit.jupiter:junit-jupiter:X.X.X')

where X.X.X is the version you want. For example in my case it was

testImplementation('org.junit.jupiter:junit-jupiter:5.6.0')

0
Huang Jinlong On

Adding the android-junit5 plugin solves the problem

plugins {
    alias(libs.plugins.androidApplication)
    alias(libs.plugins.jetbrainsKotlinAndroid)
    // use JUnit5 for tests
    id("de.mannodermaus.android-junit5") version "1.10.0.0"
}

android-junit5

0
Bob Liberatore On

You can use the official version by adding these lines to your gradle file:

android {
    testOptions {
        unitTests.all {
            useJUnitPlatform()
    }
  }
}



dependencies {
     testImplementation "org.junit.jupiter:junit-jupiter:5.8.0"
}

To continue to run your JUnit4 tests alongside Junit5, add:

testImplementation "org.junit.vintage:junit-vintage-engine:5.8.0"