Questions about Android Unit Test with gradle or android studio - android

I am writing some test cases in my project and I have bunch questions about android unit test with android studio & gradle I met in recent days and cannot get the good answers after searching.
Here are situations I have met and they are really bothering me.
Situation 1:
When I put the test cases in androidTest folder and run graldew cAT and also use the annotation #AndroidJUnit4 for the test class. I can run the unit test and get the right results. But after I just changed the #AndroidJUnit4 to #MockitoJUnitRunner (I need mock the context). The android studio or gradle cannot find any test, only tell "empty suit".
Situation 2:
When I put the test cases in test folder and run graldew test and also use the annotation #MockitoJUnitRunner. It can find the tests successfully. But I guess it only run locally. If the test cases dependent some native lib, it will give the failure message like: java.lang.UnsatisfiedLinkError: no libxx in java.library.path
So here are questions:
Question 1:
It seems that we can put the test code in src/test or src/androidTest. So what are differences between these two folders?
Question 2:
What are differences between gradlew cAT and gradle test? Are these two commands related to folder (test/androidTest folder I mentioned) in projects?
Question 3:
In my situation, I need write some test cases, which dependent the Context and native so. What should I do for that?

As this is actually 3 questions, it might have been best to create 3 separate SO questions. In any event, here are the answers:
Answer 1:
The src/test folder is meant for "regular" JUnit unit tests. These are tests that run in a regular JVM.
The src/androidTest folder is meant for any tests that require an Android device or emulator to be running. This is where your Espresso tests would live.
Answer 2:
The command gradlew cAT or gradlew connectedAndroidTest runs any tests which require a connected device (cAT standing for Connected Android Test) that are in the src/androidTest directory, while the command gradle test runs just unit tests, in src/test directory.
Answer 3:
If your unit tests depend on Context, consider using Robolectric for your unit tests. This will give you access to Context. Good examples for how to use Robolectric can be found in Corey Latislaw's "Android Katas" repo.
EDIT
Situation 1:
I'm not sure if this is what you are experiencing, but when I have run into this "Empty test suite" error (when I clearly have tests in the directory), it was because I forgot to include the Android JUnit Test Instrumentation Runner in my module's build.gradle file. Include it in the defaultConfig section of your android section, like this:
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.kiodev.example"
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}

Related

Android Studio 2.3 doesn't have Test Instrumentation specifier in UI

After updating to Android Studio 2.3 when I try to run some espresso tests I get the following error:
Test running failed: Unable to find instrumentation info for: ComponentInfo{com.example.android/android.test.InstrumentationTestRunner}
Empty test suite.
This was easily fixable in the past where in the Run Configuration I could specify my own InstrumentationRunner. Now I can't seem to find this option so I can't really specify my runner class now.
Note that my build gradle does contain
defaultConfig {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
resConfigs "en", "es"
}
I ran into this problem this morning. I deleted the old run configuration (the one that was created before you specified the new runner via build.gradle). I re-ran the tests and the new runner was picked up by Android Studio.
On Android Studio 2.3 this feature is not available as this was an optional to specify the Instrumentation Runner package/class in previous versions of Studio. But Android 2.3 is smart enough to pick this from your build.gradle file provided you have defined Instrumentation package runner there.
The following setup fixed the issue
productFlavors {
doTheTests {
minSdkVersion 18
testInstrumentationRunner "com.company.app.test.TestRunner"
if (System.getenv('CONTINUOUS_INTEGRATION').equals("true")) {
testInstrumentationRunnerArguments(package: "com.company.app.test")
}
}
}
Because Android Studio doesn't allow the testInstrumentationRunnerArguments but executing the tests through terminal indeed requires it!
Obviously on the terminal / CI system, set an environment variable like:
export CONTINUOUS_INTEGRATION=true
What helped to me - starting the test from command line then syncing the project.

Android Studio 1.1, simple junit test setup

I have read around, there are a number of extensive answers (like this one) but the Android world evolves so fast that they seem to be a bit outdated and the official documentation still refers to Eclipse with ADT.
I am running AS 1.1 and I am trying to setup simple junit tests to run on the emulator, without Robolectric. If I don't include junit in my build.gradle, it can't find #After, #Before and #Test and I get package org.junit does not exist. Upon adding
// unit tests
androidTestCompile 'junit:junit:4.11'
the error becomes
Error:duplicate files during packaging of APK
[...]/app/build/outputs/apk/app-debug-test-unaligned.apk
Path in archive: LICENSE.txt
Origin 1: [...]/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/42a25dc3219429f0e5d060061f71acb49bf010a0/hamcrest-core-1.3.jar
Origin 2: [...]/.gradle/caches/modules-2/files-2.1/junit/junit/4.11/4e031bb61df09069aeb2bffb4019e7a5034a4ee0/junit-4.11.jar
You can ignore those files in your build.gradle:
android {
packagingOptions {
exclude 'LICENSE.txt'
}
}
Following the console suggestion of excluding LICENSE.txt, it then works but it feels like a hack. So I'm wondering, am I maybe missing something? Thanks.
Android Studio unit testing support comes in 1.1 Beta 4 (release announcement) with Gradle plugin version 1.1.0-rc1.
More info in official document.
However it is experimental feature for now. E.g. it breaks installDebug gradle task.
For using JUnit in instrumentation tests there is good guide for Espresso library and another covering new AndroidJUnitRunner.
If it's any use I set up a boiler plate project allowing the use of Unit tests and Espresso tests by the use of switching build variants. You won't need the use of any third party plugins with this.
https://github.com/hitherejoe/Android-Boilerplate

Android Studio Unit Testing: unable to find instrumentation OR class not found ex

I have a test suite within my Android studio that has the following dir structure:
-MainProject
-src
--com
--tests
--java.xx.xxx.xx.test
Within my AndroidManifest, I have the following:
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="tests.java.xxx.xxx.xxx.test" />
When I run my tests from the command line using: ./gradlew connectedInstrumentTest, I simply get:
Tests on Nexus 5 - 4.4.2 failed: Instrumentation run failed due to 'java.lang.ClassNotFoundException'
When I run the tests from inside Android Studio I get:
Running tests
Test running startedTest running failed: Unable to find instrumentation info for: ComponentInfo{tests.xxx.xxx.xxx.xxx.test/android.test.InstrumentationTestRunner}
Empty test suite.
I also have the testPackageName specified in my defaultConfig in the build.gradle file. Am running Android Studio 0.4.6 on Ubuntu 12.0.4.
Any ideas?
I had the same problem and could not find anything on the net. The answer was pretty simple: You have to edit the RunConfiguration of your test so that it is not a Android Test but a JUnit test.
So basically I did the following:
Clicked "Edit Configuration"
Clicked "Add new Configuration" and chose JUnit
Inserted a name and the and chose "All in package" at Test kind.
That's it.
I had the same problem, what happened to me was an error with the configurations of tests.
Be sure that you have the correct base configurations for testing like those below in the image:
If you don't have an Android Instrumented Tests configuration, you can create one from the yellow arrow.
PS: Moreover check that classes referenced by configurations really
exists and the package name is correct
I also get error like this and I added the following line in build.gradle file as shown in https://google.github.io/android-testing-support-library/docs/espresso/setup/index.html and it's working. I hope it will also help you :-)
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
Basically three things to cross check:
Make sure your have added testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
in your defaultconfig of build.gradle of that project/ module (in case of sub module)
Make sure you have added following test compile dependencies:
androidTestCompile 'com.android.support.test:rules:0.5'
androidTestCompile 'com.android.support:support-annotations:25.2.0'
androidTestCompile 'com.android.support.test:runner:0.5'
Make sure you are adding your test files to the AndroidTest folders and not just to test folder.
I tried various methods but none fixed the issue for me. What I did is simply make a copy of the java test file into the same exact folder but with a different name and deleted the original.
I believe this issue was originally caused by moving my test class from the project test folder into the androidTest folder.
I removed the entry android.support.test.runner.AndroidJUnitRunner from the Android Test configuration and it started to run the tests for me

Android gradle test framework: single class

Is it possible to run a single test class using the new Android gradle build framework?
I have a test package that has multiple test classes (All of them are InstrumentationTestCase classes). I've been able to setup my build.gradle file to run the test package
defaultConfig{
testPackageName "com.company.product.tests"
testInstrumentationRunner "android.test.InstrumentationTestRunner"
}
But is there a way to test only one test case in that package? Otherwise I'll be using the age old adb shell am instrument -w .......
P.S. I don't have time right now to switch to Roboelectric, but I do see that its pretty much the defacto framework nowadays.
Using android.test.InstrumentationTestRunner no, this is not possible. You do, however, have options:
Custom Test Runner
Extend android.test.InstrumentationTestRunner
Add a buildConfigField 'String', 'TEST_NAME', '${testName}', where testName is '"${project.properties.get("test")}"' if set, otherwise null
In your runner, only run tests that match BuildConfig.TEST_NAME (if null, run all tests)
Replace the testInstrumentationRunner with your custom runner
Run tests with ./gradlew connectedCheck -Ptest=com.example.Test.testSomething
Use Spoon
Spoon is an excellent test runner extension that, among other things (like beautiful multi-device test reports), lets you run individual tests. Since you're using gradle, I recommend the Spoon Gradle Plugin, which has an example of exactly what you want to do in its README.
Update: Run Individual Unit Tests with Android Gradle Plugin
With the addition of unit testing support, Android now supports running individul unit tests.
This is just an anchor task, actual test tasks are called testDebug and testRelease etc. If you want to run only some tests, using the gradle --tests flag, you can do it by running ./gradlew testDebug --tests='*.MyTestClass'.
Source
Edit: I should also add that Spoon is a drop-in replacement for running tests. You will not have to modify anything but a few lines in your build script to use it.
As answered in https://stackoverflow.com/a/32603798 there is now
android.testInstrumentationRunnerArguments.class

Gradle Android testing

I'm new to gradle and Android Studio, and I'm trying to figure out how to run tests. I followed instructions in http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Testing and I'm able to run Instrument Tests but only executing /gradlew connectedInstrumentTest.
I'm having troubles understanding the other check tasks, that don't execute any code in my app.
This is what ./gradlew tasks prints
...
Verification tasks
------------------
check - Runs all checks.
connectedCheck - Runs all device checks on currently connected devices.
connectedInstrumentTest - Installs and runs the tests for Build 'Debug' on connected devices.
deviceCheck - Runs all device checks using Device Providers and Test Servers.
...
If check runs all checks... shouldn't it run the ones I get from connectedInstrumentTest?
Also, how can I run tests that don't need the Android environment? Should I place them under /test/java ? If so, what command should I run to execute them?
Sorry if these questions seem very obvious, but I just haven't been able to find any answer to these questions in the docs.
Thank you!
Edit:
So I have made some progress here.
It looks like check is not doing anything. It would be (right now) up the developer to add dependant tasks to check to run some JUnit tests. You will need to have to create a task, make it find the sources, compile them and run them.
connectedCheckand connectedInstrumentTest: runs instrumentationTest in the device. (this always worked).
deviceCheck: This is useful, as the docs say, for Continuos integration testing.
If check runs all checks... shouldn't it run the ones I get from connectedInstrumentTest?
you can have to run connectedInstrumentTest task as dependency to check task.
check.dependsOn connectedInstrumentTest
How can I run tests that don't need the Android environment?
For android projects we can discussed about 3 types of Tests
Junit Test
Robolectric Test
Instrument Test
Junit test
We can't use plain junit test to check android related classes. What we can do is separate core java classes to a java library project and add that dependency to android project.
Robolectric Test
We can use robolectric test to run the unit tests outside of the Emulator. This makes the tests fast and easy to configure with CI servers.
To run robolectric test we use gradle-android-test-plugin
It clearly describes how to use that plugin.
Project structure
We have to use default folder structure in order to use this plugin. We have to use folder called 'test' to keep robolectric tests:
MyProject/
| settings.gradle
| build.gradle
- app/
| build.gradle
-main
-java
-com.example.calculator
-test
-java
-com.example.calculator.robolectrictests
build file is
buildscript {
repositories {
mavenCentral()
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots/'
}
}
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
classpath 'com.squareup.gradle:gradle-android-test-plugin:0.9.1-SNAPSHOT'
}
apply plugin: 'android'
apply plugin: 'android-test'
repositories {
mavenCentral()
}
android {
compileSdkVersion 19
buildToolsVersion "19.0.0"
defaultConfig {
minSdkVersion 8
targetSdkVersion 19
}
}
dependencies {
compile 'com.android.support:appcompat-v7:+'
testCompile 'junit:junit:4.10'
testCompile 'org.robolectric:robolectric:2.1.+'
testCompile 'com.squareup:fest-android:1.0.+'
}
This test task will automatically executes with the check task.
Instrument Test
As you mentioned, this requires using the android emulator. That makes the tests slow, meaning that they're not a good way to do TDD.
We can use robolectric test as unit tests in the TDD process.
Instrument test we can use as integrated test in the TDD.
check SHOULD run instrumentation tests IIRC. About running non android tests. Currently the android-gradle plugin doesn't support it. I made a plugin however to run JUnit tests with robolectric so you don't need instrumentation tests. Here is the link: android-unit-test

Categories

Resources