I have an Android project that I am trying to run Instrumentation tests for using AndroidStudio, but when I try to run the whole class file for the tests, I get the exceptions as stated below :
java.lang.TypeNotPresentException: Type android.support.test.runner.AndroidJUnit4 not present
Caused by: java.lang.ClassNotFoundException: android.support.test.runner.AndroidJUnit4
Interestingly, I can run individual methods in this Instrument Test class, just not the whole class. My build.gradle file for the app is below:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
lintOptions {
abortOnError false
}
compileSdkVersion 28
defaultConfig {
applicationId "com.sarpuner.journal"
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
buildToolsVersion '27.0.3'
}
repositories {
maven { url "https://dl.bintray.com/ijabz/maven" }
}
dependencies {
androidTestImplementation 'com.android.support:support-annotations:27.1.1'
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:28.0.0-rc01'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'dev.dworks.libs:volleyplus:0.1.4'
implementation 'com.google.code.gson:gson:2.8.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'org.jsoup:jsoup:1.11.3'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.1.1'
implementation 'net.jthink:jaudiotagger:2.2.3'
api 'com.google.guava:guava:26.0-android'
}
And the InstrumentTest class is as follows:
package com.sarpuner.journal
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import android.util.Log
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
import java.io.File
private const val INSTRUMENT_TAG = "InstrumentTest"
// TODO: There is a problem here with the class run!
#RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
private val appContext = InstrumentationRegistry.getTargetContext()
#Test
fun useAppContext() {
// Context of the app under test.
assertEquals("com.sarpuner.journal", appContext.packageName)
}
#Test
fun downloadAndSaveAudio() {
val url = "http://telechargement.rfi.fr/rfi/francais/audio/jff/201808/journal_francais_facile_20h00_-_20h10_tu_20180809.mp3"
val name = "09-08-2018.mp3"
val f = File(appContext.filesDir, name)
Log.d(INSTRUMENT_TAG, f.absolutePath)
downloadAudio(url, f)
}
#Test
fun downloadAndSaveTranscript() {
val url = "https://savoirs.rfi.fr/fr/apprendre-enseigner/langue-francaise/journal-en-francais-facile-09082018-20h00-gmt"
val name = "09-08-2018.txt"
val f = File(appContext.filesDir, name)
downloadText(url, f)
}
#Test
fun addLyricsToAudio() {
}
}
Any help/guidance is much appreciated, thank you.
This is caused by Android Studio trying to execute an instrumentation test as a JUnit test.
I had to go to 'Edit Configurations...' and delete the configuration from Android JUnit group and manually add to the 'Android Instrumented Tests' group. After this I had no problem executing the tests.
In Android Studio, click Run > Edit Configurations.
https://developer.android.com/studio/run/rundebugconfig
Writing steps if someone facing issue while edit configuration for above #Bohsen's answer
In Android Studio, click Run > Edit Configurations (or press alt + shift + f10 if on Windows) to open the configuration editor.
The left panel of the window shows configurations and their groups.
Android JUnit group
Android instrumented tests
If your test is an instrumentation test, delete it from any JUnit tests groups.
If your test is a JUnit test, delete it from any instrumentation test groups.
For example, my test (DBTest.kt) was appearing in both Android JUnit and Instrumented group's section. So I deleted from JUnit group and ran it again, it was working fine.
Hopefully someone can give you a better answer as to why, but I had this exact same problem. I did the following:
Build > Clean Project,
Ran the app on the emulator
This done, I was able to get back into a state where I could run the tests again.
I had the same with:
Type androidx.test.ext.junit.runners.AndroidJUnit4 not present
I tried a lot of things before manually removing the App from the device and running the test again. Hope this helps!
For me this actually seemed to be caused by an internet connection issue. Turning off and on wifi fixed and rebuilding seemed to fix.
I got this issue when I did my tests on the emulator.
I fixed it by downloading a new project copy from the git repository.
Related
I'm trying to run a local unit test that depends on the context, and was following this guide: https://developer.android.com/training/testing/unit-testing/local-unit-tests#kotlin and I set up my project like this (following this link : https://developer.android.com/training/testing/set-up-project ):
build.gradle(app)
android {
compileSdkVersion 28
buildToolsVersion '27.0.3'
defaultConfig {
minSdkVersion 21
targetSdkVersion 27
versionCode 76
versionName "2.6.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
useLibrary 'android.test.runner'
useLibrary 'android.test.base'
useLibrary 'android.test.mock'
}
testOptions {
unitTests.returnDefaultValues = true
unitTests.all {
// All the usual Gradle options.
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen { false }
showStandardStreams = true
}
}
unitTests.includeAndroidResources = true
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
androidTestImplementation("androidx.test.espresso:espresso-core:$espressoVersion", {
exclude group: 'com.android.support', module: 'support-annotations'
})
// Espresso UI Testing dependencies
implementation "androidx.test.espresso:espresso-idling-resource:$espressoVersion"
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
testImplementation 'androidx.test:core:1.0.0'
// AndroidJUnitRunner and JUnit Rules
androidTestImplementation 'androidx.test:runner:1.1.0'
androidTestImplementation 'androidx.test:rules:1.1.0'
// Espresso Assertions
androidTestImplementation 'androidx.test.ext:junit:1.0.0'
androidTestImplementation 'androidx.test.ext:truth:1.0.0'
androidTestImplementation 'com.google.truth:truth:0.42'
implementation 'androidx.multidex:multidex:2.0.0'
}
My espresso_version is espressoVersion = '3.1.0'
My test that is located in module-name/src/test/java/ looks like this:
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import com.instacart.library.truetime.TrueTime
import edu.mira.aula.shared.extensions.android.trueDateNow
import edu.mira.aula.shared.network.ConnectivityHelper
import kotlinx.coroutines.experimental.runBlocking
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import java.util.*
import java.util.concurrent.CountDownLatch
class TimeExtensionsUnitTest {
private lateinit var instrumentationCtx: Context
#Before
fun setup() {
instrumentationCtx = ApplicationProvider.getApplicationContext<Context>()
}
#Test
fun testTrueTimeValueReturnsIfInitialized() {
if (ConnectivityHelper.isOnline(instrumentationCtx)) {
runBlocking {
val countDownLatch = CountDownLatch(1)
TrueTime.build()
.withSharedPreferencesCache(instrumentationCtx)
.withConnectionTimeout(10000)
.initialize()
countDownLatch.countDown()
try {
countDownLatch.await()
val dateFromTrueTime = trueDateNow()
val normalDate = Date()
Assert.assertNotEquals(dateFromTrueTime, normalDate)
} catch (e: InterruptedException) {
}
}
}
}
Everytime I run it, it gives me:
java.lang.IllegalStateException: No instrumentation registered! Must run under a registering instrumentation.
at androidx.test.platform.app.InstrumentationRegistry.getInstrumentation(InstrumentationRegistry.java:45)
at androidx.test.core.app.ApplicationProvider.getApplicationContext(ApplicationProvider.java:41)
If I run it as a Instrumental Test(changing the package) it runs without errors.
But I thought that this guide was exactly to be able to run unit test using Android Framework classes such as Context.
I even tried run that class UnitTestSample but the same error occurs.
I also removed all android.support dependencies from my project
Any ideas on how to solve it?
Update
You should no longer encounter this error if youre using the latest gradle version.
I also encountered this issue.
If you look at migrating to Robolectric 4.0 here, it suggest to add the following line in your gradle.properties.
android.enableUnitTestBinaryResources=true
The problem is that, if you add this you your gradle.properties, it will output this warning:
WARNING: The option setting
'android.enableUnitTestBinaryResources=true' is experimental and
unsupported.
Now, if you look at Robolectric releases here. You could see that this is a known issue where they state that
Android Gradle Plugin may report the following warning, which may be safely ignored: WARNING: The option setting 'android.enableUnitTestBinaryResources=true' is experimental and unsupported.. Android Gradle Plugin 3.4 will resolve this issue.
I believe unless you could update you gradle to 3.4. You won't be able to solve this issue.
What I did instead was to include Robolectric 4.0 as dependency.
testImplementation "org.robolectric:robolectric:4.0.2"
and annotate my test class with
#RunWith(RobolectricTestRunner::class)
This should make your test work.
Now when you run the test, you'll notice that Robolectric will log the following:
[Robolectric] NOTICE: legacy resources mode is deprecated; see
http://robolectric.org/migrating/#migrating-to-40
Ignore this for now but as soon as you could update your gradle, migrate to the new Robolectric testing.
I follow the official guide also met this issue, fix it with below steps.
Add testImplementation in app build.gradle
// Required -- JUnit 4 framework
testImplementation 'junit:junit:4.13.1'
testImplementation 'androidx.test:core-ktx:1.3.0'
testImplementation 'androidx.test.ext:junit-ktx:1.1.2'
// Robolectric environment
testImplementation 'org.robolectric:robolectric:4.4'
// Optional -- truth
testImplementation 'androidx.test.ext:truth:1.3.0'
testImplementation 'com.google.truth:truth:1.0'
// Optional -- Mockito framework
testImplementation 'org.mockito:mockito-core:3.3.3'
The official guide missed two testImplementations
testImplementation 'androidx.test.ext:junit-ktx:1.1.2'
testImplementation 'org.robolectric:robolectric:4.4'
Add testOptions block in app build.gradle
android {
// ...
testOptions {
unitTests.includeAndroidResources = true
}
}
Add #RunWith(AndroidJUnit4::class) to your test class
Example:
import android.content.Context
import android.os.Build.VERSION_CODES.Q
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
#RunWith(AndroidJUnit4::class)
#Config(sdk = [Q])
class UnitTestWithContextDemoTest {
private val context: Context = ApplicationProvider.getApplicationContext()
fun test_getPackageName() {
assertThat(context.packageName).contains("your_package_name")
}
}
NOTE
#Config(sdk = [Q]) is required when your targetSdkVersion greater than 29. Because robolectric NOT support targetSdkVersion greater than 29.
Spend hours on similar issue, and the problem wasn't in dependencies, rather in AndroidStudio itself Based on the answer:
IDE tries to run local unit tests instead of instrumented
.
Make sure it's run as instrumented test (red is local tests, green - instrumented):
After added instrumented test for the class it's run as expected under instrumented. How I done this? 2 ways I found:
1) Edit configuration (as on the last screenshot) and adding function manually
2) Under Project tap (top left corner) I selected Tests instead of android, found the test, right click - create test. After this step all new tests are run under instrumented tests
I had similar error and was struggling a lot to fix it. My problem was that I was mixing AndroidJUnit4, InstrumentationRegistry, ApplicationProvider and AndroidJUnitRunnerversions / packages. Make sure they all are of the same generation. These are the classes that made it all run for me:
androidx.test.runner.AndroidJUnitRunner
androidx.test.platform.app.InstrumentationRegistry
androidx.test.ext.junit.runners.AndroidJUnit4
androidx.test.core.app.ApplicationProvider
for these I needed the following in the dependencies part of my build.gradle
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
androidTestImplementation 'androidx.test:core:1.1.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation "com.android.support:support-annotations:27.1.1"
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
And of course the correct
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
in my defaultConfig of the build.gradle
Next things are not mentioned on google test guide, but they are what I found:
androidx.test in case of unit tests is just an interface/api (I don't know what about instrumented tests) and it needs implementations, which is robolectric library.
That's why robolectric dependency is also required:
testImplementation "org.robolectric:robolectric:{version}"
#RunWith(AndroidJUnit4.class)
is required. To get nondeprecated class you need to add:
testImplementation "androidx.test.ext:junit:{version}". By the way this dependency has transitive junit4 dependensy.
Also you can faced with: Failed to create a Robolectric sandbox: Android SDK 29 requires Java 9 (have Java 8) in case you use java 8 and compileSdkVersion 29 or above. Here you can find how to deal with it.
Make sure to put your instrumentation tests (tests you run with a Runner) in androidTest and not just test
in my case I was using getApplicationContext() in a fragment from the test package, I just change it to getContext(). and this fixed my crash!
In my case, changing the test method name fixed the issue.
Most probably the Android Studio cached the methods with indexes that caused a problem.
[Note : To remember this ]
AndroidJUnit4.class | used to run testcases of intrumentation type inside source set called androidTest [which requires phone or emulator]
AndroidJUnit4ClassRunner | used to run testcases for local test inside source set called test folder. [ no phone /emulator required]
Exception or Improvement Case | Using Robo-electric and supported junit4 dependency, then AndroidJUnit4.class can be used inside test folder to test local test.
Use this dependency[try to add latest]
testImplementation "org.robolectric:robolectric:4.4"
Then in your test class, use #RunWith(AndroidJUnit4::class)
Example : #RunWith(AndroidJUnit4::class)
-------For Reference-----
#RunWith(AndroidJUnit4::class)
class TasksViewModelTest {
#Test
fun addNewTask_setsNewTaskEvent() {
// Given a fresh TasksViewModel
var tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
// When adding a new task
tasksViewModel.addNewTask()
// Then the new task event is triggered
}
}
Looks like you forgot to annotate your TimeExtensionsUnitTest with #RunWith(AndroidJUnit4::class) re: https://github.com/android/android-test/issues/409. I can reproduce the error by commenting that out in my own tests.
That said, this is not the only way to get your error. I originally encountered it when I was updating some old Robolectric tests to use some AndroidX apis (http://robolectric.org/androidx_test/), including switching away from #RunWith(RobolectricTestRunner::class). In my case, I was trying to use a context in my #BeforeClass with ApplicationProvider.getApplicationContext<Context>(), which is wrong in AndroidX, even though it was ok using Roboletric's runner with appContext = RuntimeEnvironment.getApplication().applicationContextappContext. Fortunately I was able to move the logic into my #Before call to fix things without a significant hit.
More generally, I've noticed documentation out there isn't fully comprehensive all in one place explaining the migration from the very old android.support.test Android Testing Support Library and Roboletric dependencies to AndroidX, but here's some other notes:
If I want to run real instrumentation tests on an emulator/physical device, ensure that the tests are under src/androidTest. This also means I need to change in my build.gradle file the dependencies on androidx.test libraries from testImplementation => androidTestImplementation, and also explicitly set a testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" in the defaultConfig section.
https://developer.android.com/training/testing/local-tests
https://developer.android.com/training/testing/instrumented-tests
If I'm happy with using Robolectric to run those tests as local, I can keep them under src/test, declare the dependencies using testImplementation, and don't need the testInstrumentationRunner. It's nice that I don't have to change the code to do this since I'm using the AndroidX Test APIs, which Roboletric is compatible with as of v4.0.
I got the same problem and here is how i fixed it:
move my test class to the "androidTest" package
annotate the test class with #RunWith(AndroidJUnit4.class)
Hope this can help
Simply check your import section:
import androidx.test.runner.AndroidJUnit4;
I'm trying to run a local unit test that depends on the context, and was following this guide: https://developer.android.com/training/testing/unit-testing/local-unit-tests#kotlin and I set up my project like this (following this link : https://developer.android.com/training/testing/set-up-project ):
build.gradle(app)
android {
compileSdkVersion 28
buildToolsVersion '27.0.3'
defaultConfig {
minSdkVersion 21
targetSdkVersion 27
versionCode 76
versionName "2.6.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
useLibrary 'android.test.runner'
useLibrary 'android.test.base'
useLibrary 'android.test.mock'
}
testOptions {
unitTests.returnDefaultValues = true
unitTests.all {
// All the usual Gradle options.
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen { false }
showStandardStreams = true
}
}
unitTests.includeAndroidResources = true
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
androidTestImplementation("androidx.test.espresso:espresso-core:$espressoVersion", {
exclude group: 'com.android.support', module: 'support-annotations'
})
// Espresso UI Testing dependencies
implementation "androidx.test.espresso:espresso-idling-resource:$espressoVersion"
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
testImplementation 'androidx.test:core:1.0.0'
// AndroidJUnitRunner and JUnit Rules
androidTestImplementation 'androidx.test:runner:1.1.0'
androidTestImplementation 'androidx.test:rules:1.1.0'
// Espresso Assertions
androidTestImplementation 'androidx.test.ext:junit:1.0.0'
androidTestImplementation 'androidx.test.ext:truth:1.0.0'
androidTestImplementation 'com.google.truth:truth:0.42'
implementation 'androidx.multidex:multidex:2.0.0'
}
My espresso_version is espressoVersion = '3.1.0'
My test that is located in module-name/src/test/java/ looks like this:
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import com.instacart.library.truetime.TrueTime
import edu.mira.aula.shared.extensions.android.trueDateNow
import edu.mira.aula.shared.network.ConnectivityHelper
import kotlinx.coroutines.experimental.runBlocking
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import java.util.*
import java.util.concurrent.CountDownLatch
class TimeExtensionsUnitTest {
private lateinit var instrumentationCtx: Context
#Before
fun setup() {
instrumentationCtx = ApplicationProvider.getApplicationContext<Context>()
}
#Test
fun testTrueTimeValueReturnsIfInitialized() {
if (ConnectivityHelper.isOnline(instrumentationCtx)) {
runBlocking {
val countDownLatch = CountDownLatch(1)
TrueTime.build()
.withSharedPreferencesCache(instrumentationCtx)
.withConnectionTimeout(10000)
.initialize()
countDownLatch.countDown()
try {
countDownLatch.await()
val dateFromTrueTime = trueDateNow()
val normalDate = Date()
Assert.assertNotEquals(dateFromTrueTime, normalDate)
} catch (e: InterruptedException) {
}
}
}
}
Everytime I run it, it gives me:
java.lang.IllegalStateException: No instrumentation registered! Must run under a registering instrumentation.
at androidx.test.platform.app.InstrumentationRegistry.getInstrumentation(InstrumentationRegistry.java:45)
at androidx.test.core.app.ApplicationProvider.getApplicationContext(ApplicationProvider.java:41)
If I run it as a Instrumental Test(changing the package) it runs without errors.
But I thought that this guide was exactly to be able to run unit test using Android Framework classes such as Context.
I even tried run that class UnitTestSample but the same error occurs.
I also removed all android.support dependencies from my project
Any ideas on how to solve it?
Update
You should no longer encounter this error if youre using the latest gradle version.
I also encountered this issue.
If you look at migrating to Robolectric 4.0 here, it suggest to add the following line in your gradle.properties.
android.enableUnitTestBinaryResources=true
The problem is that, if you add this you your gradle.properties, it will output this warning:
WARNING: The option setting
'android.enableUnitTestBinaryResources=true' is experimental and
unsupported.
Now, if you look at Robolectric releases here. You could see that this is a known issue where they state that
Android Gradle Plugin may report the following warning, which may be safely ignored: WARNING: The option setting 'android.enableUnitTestBinaryResources=true' is experimental and unsupported.. Android Gradle Plugin 3.4 will resolve this issue.
I believe unless you could update you gradle to 3.4. You won't be able to solve this issue.
What I did instead was to include Robolectric 4.0 as dependency.
testImplementation "org.robolectric:robolectric:4.0.2"
and annotate my test class with
#RunWith(RobolectricTestRunner::class)
This should make your test work.
Now when you run the test, you'll notice that Robolectric will log the following:
[Robolectric] NOTICE: legacy resources mode is deprecated; see
http://robolectric.org/migrating/#migrating-to-40
Ignore this for now but as soon as you could update your gradle, migrate to the new Robolectric testing.
I follow the official guide also met this issue, fix it with below steps.
Add testImplementation in app build.gradle
// Required -- JUnit 4 framework
testImplementation 'junit:junit:4.13.1'
testImplementation 'androidx.test:core-ktx:1.3.0'
testImplementation 'androidx.test.ext:junit-ktx:1.1.2'
// Robolectric environment
testImplementation 'org.robolectric:robolectric:4.4'
// Optional -- truth
testImplementation 'androidx.test.ext:truth:1.3.0'
testImplementation 'com.google.truth:truth:1.0'
// Optional -- Mockito framework
testImplementation 'org.mockito:mockito-core:3.3.3'
The official guide missed two testImplementations
testImplementation 'androidx.test.ext:junit-ktx:1.1.2'
testImplementation 'org.robolectric:robolectric:4.4'
Add testOptions block in app build.gradle
android {
// ...
testOptions {
unitTests.includeAndroidResources = true
}
}
Add #RunWith(AndroidJUnit4::class) to your test class
Example:
import android.content.Context
import android.os.Build.VERSION_CODES.Q
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
#RunWith(AndroidJUnit4::class)
#Config(sdk = [Q])
class UnitTestWithContextDemoTest {
private val context: Context = ApplicationProvider.getApplicationContext()
fun test_getPackageName() {
assertThat(context.packageName).contains("your_package_name")
}
}
NOTE
#Config(sdk = [Q]) is required when your targetSdkVersion greater than 29. Because robolectric NOT support targetSdkVersion greater than 29.
Spend hours on similar issue, and the problem wasn't in dependencies, rather in AndroidStudio itself Based on the answer:
IDE tries to run local unit tests instead of instrumented
.
Make sure it's run as instrumented test (red is local tests, green - instrumented):
After added instrumented test for the class it's run as expected under instrumented. How I done this? 2 ways I found:
1) Edit configuration (as on the last screenshot) and adding function manually
2) Under Project tap (top left corner) I selected Tests instead of android, found the test, right click - create test. After this step all new tests are run under instrumented tests
I had similar error and was struggling a lot to fix it. My problem was that I was mixing AndroidJUnit4, InstrumentationRegistry, ApplicationProvider and AndroidJUnitRunnerversions / packages. Make sure they all are of the same generation. These are the classes that made it all run for me:
androidx.test.runner.AndroidJUnitRunner
androidx.test.platform.app.InstrumentationRegistry
androidx.test.ext.junit.runners.AndroidJUnit4
androidx.test.core.app.ApplicationProvider
for these I needed the following in the dependencies part of my build.gradle
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
androidTestImplementation 'androidx.test:core:1.1.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation "com.android.support:support-annotations:27.1.1"
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
And of course the correct
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
in my defaultConfig of the build.gradle
Next things are not mentioned on google test guide, but they are what I found:
androidx.test in case of unit tests is just an interface/api (I don't know what about instrumented tests) and it needs implementations, which is robolectric library.
That's why robolectric dependency is also required:
testImplementation "org.robolectric:robolectric:{version}"
#RunWith(AndroidJUnit4.class)
is required. To get nondeprecated class you need to add:
testImplementation "androidx.test.ext:junit:{version}". By the way this dependency has transitive junit4 dependensy.
Also you can faced with: Failed to create a Robolectric sandbox: Android SDK 29 requires Java 9 (have Java 8) in case you use java 8 and compileSdkVersion 29 or above. Here you can find how to deal with it.
Make sure to put your instrumentation tests (tests you run with a Runner) in androidTest and not just test
in my case I was using getApplicationContext() in a fragment from the test package, I just change it to getContext(). and this fixed my crash!
In my case, changing the test method name fixed the issue.
Most probably the Android Studio cached the methods with indexes that caused a problem.
[Note : To remember this ]
AndroidJUnit4.class | used to run testcases of intrumentation type inside source set called androidTest [which requires phone or emulator]
AndroidJUnit4ClassRunner | used to run testcases for local test inside source set called test folder. [ no phone /emulator required]
Exception or Improvement Case | Using Robo-electric and supported junit4 dependency, then AndroidJUnit4.class can be used inside test folder to test local test.
Use this dependency[try to add latest]
testImplementation "org.robolectric:robolectric:4.4"
Then in your test class, use #RunWith(AndroidJUnit4::class)
Example : #RunWith(AndroidJUnit4::class)
-------For Reference-----
#RunWith(AndroidJUnit4::class)
class TasksViewModelTest {
#Test
fun addNewTask_setsNewTaskEvent() {
// Given a fresh TasksViewModel
var tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
// When adding a new task
tasksViewModel.addNewTask()
// Then the new task event is triggered
}
}
Looks like you forgot to annotate your TimeExtensionsUnitTest with #RunWith(AndroidJUnit4::class) re: https://github.com/android/android-test/issues/409. I can reproduce the error by commenting that out in my own tests.
That said, this is not the only way to get your error. I originally encountered it when I was updating some old Robolectric tests to use some AndroidX apis (http://robolectric.org/androidx_test/), including switching away from #RunWith(RobolectricTestRunner::class). In my case, I was trying to use a context in my #BeforeClass with ApplicationProvider.getApplicationContext<Context>(), which is wrong in AndroidX, even though it was ok using Roboletric's runner with appContext = RuntimeEnvironment.getApplication().applicationContextappContext. Fortunately I was able to move the logic into my #Before call to fix things without a significant hit.
More generally, I've noticed documentation out there isn't fully comprehensive all in one place explaining the migration from the very old android.support.test Android Testing Support Library and Roboletric dependencies to AndroidX, but here's some other notes:
If I want to run real instrumentation tests on an emulator/physical device, ensure that the tests are under src/androidTest. This also means I need to change in my build.gradle file the dependencies on androidx.test libraries from testImplementation => androidTestImplementation, and also explicitly set a testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" in the defaultConfig section.
https://developer.android.com/training/testing/local-tests
https://developer.android.com/training/testing/instrumented-tests
If I'm happy with using Robolectric to run those tests as local, I can keep them under src/test, declare the dependencies using testImplementation, and don't need the testInstrumentationRunner. It's nice that I don't have to change the code to do this since I'm using the AndroidX Test APIs, which Roboletric is compatible with as of v4.0.
I got the same problem and here is how i fixed it:
move my test class to the "androidTest" package
annotate the test class with #RunWith(AndroidJUnit4.class)
Hope this can help
Simply check your import section:
import androidx.test.runner.AndroidJUnit4;
I have 2 Kotlin based AS projects. One works fine, the other doesn't. Both have an identical structure and gradle config. I'm using Kotlin 1.1.4-2 with AS 3.0b2.
The problem is that when I run code coverage, the classes I'm testing do not even show up under the coverage report. The only thing I see is R.java and BuildConfig.java, but none of my source files are being found.
All source files are Kotlin based. I'm using Spek for my unit testing. Same setup and versions as my other functional project. I tried using both JaCoCo and Jetbrains code coverage and neither works.
I apologize, I'm not able to embed pictures yet.
This is the problem:
Here's my project structure:
And here's my gradle android block:
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
minSdkVersion 16
targetSdkVersion 26
versionCode 1
versionName libraryVersion
}
buildTypes {
debug {
testCoverageEnabled = true
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
and my dependencies:
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation "io.reactivex.rxjava2:rxkotlin:2.1.0"
testImplementation 'junit:junit:4.12'
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
testImplementation 'org.jetbrains.spek:spek-api:1.1.2'
testImplementation 'org.jetbrains.spek:spek-junit-platform-engine:1.1.2'
testImplementation 'org.junit.platform:junit-platform-runner:1.0.0-M4'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.0.0-M4'
implementation 'com.android.support:appcompat-v7:26.0.1'
implementation 'com.squareup.okhttp3:okhttp-ws:3.3.1'
implementation 'com.google.protobuf:protobuf-java:2.6.1'
I've tried running
task copyTestClasses(type: Copy) {
from "build/tmp/kotlin-classes/debugUnitTest"
into "build/intermediates/classes/debug"
}
task copySdkClasses(type: Copy) {
from "build/tmp/kotlin-classes/debug"
into "build/intermediates/classes/debug"
}
before my testing and that doesn't work either.
What's strange is my other project, using the same AS version, Kotlin version, and project structure, is working fine and generating proper code coverage.
Any help would be appreciated.
Try to use JaCoco for coverage, this is a IntelliJ IDEA issue: Kotlin inline keyword causing IntelliJ IDEA Coverage reporting 0%
How to use JaCoco to get the coverage:
Making Android Studio Test Coverage works
Resume:
Click on edit configurations
Go to Run/Debug Configurations -> Defaults -> Android JUnit -> Code Coverage
Choose coverage Runner: Select JaCoCo
Apply -> OK
Run your test again and voila you will get the coverage
Kotlin announced the new kotlinx-kover Gradle plugin compatible with JaCoCo and IntelliJ.
It resolves the problem with inline functions and maybe more.
plugins {
id("org.jetbrains.kotlinx.kover") version "0.5.0"
}
Once applied, the plugin can be used out of the box without additional configuration.
Watch its YouTube announcement video and also track its roadmap from this youtrack issue.
I have been trying to run simple instrumented tests in Android Studio, without any success.
I followed the guide for Unit Tests and it works fine. Now, I would like to tests components which are difficult to mock.
When I follow the guide on instrumented tests, I end up with dependency errors.
What I did:
Install the Android Testing Support Library (Android Support Repository, rev 17).
Create a directory androidTest in src. Add Java folder + package ending with "test".
Add a simple Test class
#RunWith(AndroidJUnit4.class)
public class ServerRequestInstrumentationTest {
#Test
public void test(){
LogC.d("Here we go testing !");
}
}
Add a simple TestSuit.
#RunWith(Suite.class)
#Suite.SuiteClasses({ServerRequestInstrumentationTest.class})
public class TestSuit {
public TestSuit(){}
}
Modify my gradle file to add dependencies.
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.mydomain.app"
minSdkVersion 9
targetSdkVersion 22
versionCode 28
versionName "2.0.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
lintOptions {
disable 'MissingTranslation'
}
}
}
sourceSets { main { java.srcDirs = ['src/main/java'] } }
}
dependencies {
compile 'com.android.support:support-v4:22.2.0'
compile 'com.android.support:appcompat-v7:22.2.0'
wearApp project(':wear')
compile project(':moreapps')
compile project(':lib_repair')
compile project(':bugreport')
//testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.10.19'
androidTestCompile 'junit:junit:4.12'
androidTestCompile 'org.hamcrest:hamcrest-library:1.1'
androidTestCompile 'com.android.support.test:runner:0.3'
androidTestCompile 'com.android.support.test:rules:0.3'
}
I just added the line androidTestCompile 'junit:junit:4.12', otherwise the annotation #RunWith(AndroidJUnit4.class) wasn't recognized.
Now when I launch the test, I get one Gradle build error.
Error:Execution failed for task ':app:dexDebugAndroidTest'.
com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command
'/usr/lib/jvm/jdkoracle/bin/java'' finished with non-zero exit value 2
Any suggestion ? Did I miss something about the testing library ?
Thank you
Okay, finally got it working.
After a little search, I found out that the Gradle console output an error :
AGPBI: {"kind":"simple","text":"UNEXPECTED TOP-LEVEL EXCEPTION:","sources":[{}]}
AGPBI: {"kind":"simple","text":"com.android.dex.DexException: Multiple dex files define Lorg/hamcrest/TypeSafeMatcher;","sources":[{}]}
After I changed one line in my gradle build, Gradle built the project successfuly and I was able to run the simple instrumented test.
Line to change:
androidTestCompile 'org.hamcrest:hamcrest-library:1.1'
to
testCompile 'org.hamcrest:hamcrest-library:1.1'
I don't know why Gradle complains in one case and not the other though...
Instrumentation tests are different to Unit Tests. You have to extend your test classes by specific classes. For more information about that take a look at Android Testing Fundamentals. Also you do not need JUnit for Instrumentaion tests.
Furthermore you have to switch your build variants from Unit Tests to Android Instrumentation Tests, as described here Unit testing in android studio
EXAMPLE:
Here an example for an instrumentaion test in android:
public class ExampleITest extends AndroidTestCase {
#Override
public void setUp() throws Exception {
super.setUp();
InputStream is = getContext().getAssets().open("test.xml");
XmlParser parser = new XmlParser(getContext());
parser.parse(is);
...
}
#MediumTest
public void testSomething() throws Exception {
// test some data your parser extracted from the xml file
...
}
}
As you can see, you can access context, etc.
For this test no specific dependencies are necessary in the gradle file.
I haven't heard about Instrumantation tests just with annotions. maybe i should look it up on the web ;)
Althought #Gordark's answer will not throw any error It's not a proper solution if you want to use Hamcrest in your instrumentation tests, it will work just for your local JVM tests.
I found that using 1.3 version of hamcrest-library actually worked, just replace
androidTestCompile 'org.hamcrest:hamcrest-library:1.1'
with
androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
And it should work. I think it's something about conflicting versions of junit and hamcrest. I guess hamcrest 1.1 depends on a version of junit bellow 4.12, and hamcrest 1.3 depends on junit v4.12
Your answer contains a hint to the problem. You state there that Gradle gives an error. This is because one of the other dependencies for androidTestCompile depends on hamcrest. This is called a transitive dependency. It also means that you can completely remove your explicit requirement for hamcrest. Your change adds hamcrest as a dependency for testCompile which is used for unit tests run locally on your development machine rather than on an Android device or emulator. If you aren't making unit tests you don't need this. Even when you do start writing unit tests, you probably don't need an explicit dependency on hamcrest.
I keep running into the following error when trying to execute my tests in Android Studio: Test running failed: Unable to find instrumentation info for: ComponentInfo{.test/android.support.test.runner.AndroidJUnitRunner}
My test class is in the androidTest/java directory and has a constructor. My build.gradle is correct too. Any help is appreciated.
Test Class
#RunWith(AndroidJUnit4.class)
#LargeTest
public class AndroidUITests extends ActivityInstrumentationTestCase2<UserActivity>{
private UserActivity userActivity;
public AndroidUITests() {
super(UserActivity.class);
}
#Before
public void setUp() throws Exception {
super.setUp();
injectInstrumentation(InstrumentationRegistry.getInstrumentation());
userActivity = getActivity();
}
#Test
public void testPhoneIconIsDisplayed() {
// When the phone_icon view is available,
// check that it is displayed.
onView(ViewMatchers.withId(R.id.groupCreate)).perform(click())
.check(matches(withText("Enter a name")));
}
}
app/build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
testInstrumentationRunner
"android.support.test.runner.AndroidJUnitRunner"
}
packagingOptions {
exclude 'LICENSE.txt'
}
}
dependencies {
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
}
While the question is already answered, figured it was worth posting for future visitors.
Make sure you check the logcat logs to ensure something isn't causing issues (crash) before the test is even run. I had bad code in my #BeforeClass block which resulted in the "Empty Test Suite" message in Android Studio despite having properly set the test runner.
You have to update the test "Edit Configuration" and include the AndroidJUnitRunner as the instrumentation runner.
I found the solution in this video:
https://youtu.be/TGU0B4qRlHY?t=9m36s
Updated
Adding what #loeschg suggest:
Make sure you check the logcat logs to ensure something isn't causing issues (crash) before the test is even run. Bad code in the #BeforeClass block could resulted in the "Empty Test Suite" message in Android Studio despite having properly set the test runner.
If you get such error message:
Class not found: "com.example.product.package.name.SomeSpecificTest" Empty test suite.
You need to make sure if your Espresso test is added under Android Instrumented Tests section in Run/Debug Configurations.
It seems like Android Studio 3.1.3 is sometimes adding it incorrectly to Android JUnit section instead.
Make sure it looks something like this:
Also, worth mentioning that I've noticed, that this issue occurs for me while a non Debug build variant is selected.
I'm fairly certain android.support.test.runner.AndroidJUnitRunner is provided by the runner library.
Install the Android Support Repository (which you've already done)
Add runner to your dependencies
it should look like this
dependencies {
...
androidTestCompile 'com.android.support.test:runner:0.2'
}
If anyone still bother with this in 2018, here is working setup:
build.gradle (required):
<...snip...>
android {
defaultConfig {
<...snip...>
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// ^^^ here it is (first)!
}
<...snip...>
dependencies {
<...snip...>
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
// ^^^ all three required ^^^ (second)
}
And in instrumented tests (required too):
import androidx.test.espresso.Espresso.onData
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.*
import androidx.test.espresso.assertion.ViewAssertions.*
import androidx.test.espresso.matcher.RootMatchers.*
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import org.hamcrest.Matchers.*
import org.junit.Test
import org.junit.runner.RunWith
#RunWith(AndroidJUnit4::class)
#LargeTest
class ApplicationTest {
#Test
fun thruStillThrullyThrue() {
// do interaction with some UI
onView(withId(R.id.myButtonOnMyActivity)).perform(click())
// assert expected result
onView(withId(R.id.myTextViewOnMyActivity)).check(matches(isDisplayed()))
}
}
// (third)
My issue was that the field 'testInstrumentationRunner' is specified in the build.gradle (app). Change that to the androidx if you are using it (androidx.test.runner.AndroidJUnitRunner)
Hope it helps someone, cheers!