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
Related
I've been trying to get the code coverage for my local unit tests and haven't been successful.
Here's a reference on what I mean by local unit tests.
https://developer.android.com/training/testing/unit-testing/local-unit-tests.html
To run my unit tests, I use the following gradle command.
./gradlew clean testDebugUnitTest
This task will run the unit tests but when I view the jacoco file that gets generated (testDebugUnitTest.ec) in "build/jacoco" folder, it always shows an empty coverage.
I've enabled the coverage in my build.gradle file as follows.
android {
buildTypes {
debug {
testCoverageEnabled true
}
}
}
but that doesn't seem to help. Is there something that I am missing?
Note that if I run the local unit tests through Android Studio, everything works fine. I clicked on my "tests" module and click on "Run tests with coverage".
So, I found out the answer to my own question. Oddly enough, it looks like running "testDebugUnitTest" with the "testCoverageEnabled" flag set is the correct way to do it.
However, since apparently gradle's jacoco version is different than the jacoco version that is running in Android Studio and my CI system (Jenkins), it wasn't able to be viewed due to some backwards compatibility issue in jacoco.
To fix the issue, I set my jacoco version in gradle to the same one in my Android Studio (Intellij) and Jenkins.
jacoco {
toolVersion = '0.7.0.201403182114'
}
I put the code above in my build.gradle file.
I've had to solve the problem myself and I was actually expecting the default gradle plugin will have support for code coverage for local unit tests. Unfortunately, out of the box, there is no support for this, even on android gradle plugin version 3.0.1.
Fortunately, however, there is a simple third-party plugin we can use to generate jacoco test reports: gradle-android-junit-jacoco-plugin
To use it, you need to register this plugin's repository and classpath into your root-level build.gradle. Your build.gradle file might look different, but this is what worked for me:
buildscript {
repositories {
// ... there may be other repositories here
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
// ... other classpaths here too
classpath "gradle.plugin.com.vanniktech:gradle-android-junit-jacoco-plugin:0.11.0"
}
}
And to generate the report, one can simply do this:
./gradlew jacocoTestReportDebug
The output will be in one of your modules build folder, for example:
your-module/build/reports/coverage/debug/index.html
Note I verified this working on android gradle plugin 3.0.1.
For reference, my source is this answer from Niklas, creator of the plug-in: https://stackoverflow.com/a/33064500/390718
I am trying to run unit test on a separate task from the UI tests that I have within the integration tests in Android Studio, unfortunately I have to use
apply plugin: 'com.android.application'
in the build.gradle file so I cannot add the custom test tasks as far as I can tell. Since the UI tests are tagged as "#Test" and extend InstrumentationTestCase they get run whenever
gradle connectedCheck
is called which is not needed, instead I want one gradle command to run UI tests and one to run unit tests. I figured that I would be able to leverage tagging the UI tests as LargeTests but have not been able to complete a gradle task that can do this. I am not able to use the "test" task in the build.gradle since we are using the com.android.application plugin, and advice?
Thanks
You can do this from command-line without modifying the build.gradle file:
./gradlew cAT -Pandroid.testInstrumentationRunnerArguments.notAnnotation=android.test.suitebuilder.annotation.LargeTest
What ended up working for me is adding the
#LargeTest
using
import android.support.test.filters.LargeTest;
annotation to the tests I needed and then adding the following lines to the build.gradle
if(!project.hasProperty('android.testInstrumentationRunnerArguments.annotation')) {
testInstrumentationRunnerArgument 'notAnnotation', 'android.support.test.filters.LargeTest'
}
this way unless I specify in the command line to run the large tests they will,be ignored. To run the large tests use:
gradle cAT -Pandroid.testInstrumentationRunnerArguments.annotation=android.support.test.filters.LargeTest
I have the android application and I want to use Espresso framework to create test automation tools and tests. But I don't want to create something in my app and want separate module with Espresso that will start my app and test it using Espresso. I use Android Studio. So.. Have you any ideas how to solve this problem?
You can use a library module specialised for instrumentation tests. Basically just create a library module but use a different plugin:
apply plugin: 'com.android.test' // A plugin used for test-only-modules
Also you need to changep your android part in your build.gradle file in your test module a little:
android {
[...]
defaultConfig {
[...]
testApplicationId "com.yourcompany.yourapp.test"
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
[...]
// Set the target app project.
// The module specified here should contain the
// production code test should run against.
targetProjectPath ':app'
}
Then add your app and all your espresso libraries etc. in your test module's dependencies:
dependencies {
implementation project(':app')
// All your test dependencies etc.
implementation "androidx.test.espresso:espresso-core:$espresso_version"
}
Using a gradle sync and run tests you can then execute your tests locally. You'll also get all your normal gradle tasks for that module which you can use to assemble your test APK etc. if you need it to test externally e.g. in Firebase Test Labs.
I am writing junit tests on android project using the new unit test support http://tools.android.com/tech-docs/unit-testing-support.
While the unit tests run on the 'com.android.application' module perfectly but they always fail on the 'com.android.library' modules. This has not been documented in http://tools.android.com/tech-docs/unit-testing-support . So I wonder whether I am the culprit.
When I write those tests on library modules, the tests can not find the classes on the module and always gives following errors:
package does not exist
error: cannot find symbol
The android unit test support is in experimental phase right now, but is there a solution to it.
UPDATE
I have added this issue to android issue tracker https://code.google.com/p/android/issues/detail?id=161038
It looks like the task to compile the unit tests doesn't depend on the task to compile the library code.
The following fixed it for me:
afterEvaluate {
tasks['assembleDebugUnitTest'].dependsOn(tasks['assembleDebug'])
}
I run the tests using
./gradlew testDebug
If you don't want to modify your build.gradle, manually specify the assembleDebug task on the command line should also do the trick:
./gradlew assembleDebug testDebug
In my android library project I also failed to get the tests running. What I did was create a test application that uses the library and wrote tests in the application that call the library methods.
This might not be the ideal solution, but was the way we got this to work.
Have a look over here https://github.com/nenick/AndroidStudioAndRobolectric
There you can run unit tests on libraries and flavors. And no you don't need to use Robolectric as Gaurav Vashisth stated. You can if you want to.
Here is an example of JUnit test in a library module
Our Android app needs automated testing, and our group is using Robotium to handle that for us. This is no problem for unit tests, but we're also writing a set of end-to-end integration tests to exercise not only the client by the back-end servers as well. I've got some tests that do this, but if possible, I'd like to break them out separately from the unit tests so that our continuous integration builds don't require a live server to be running in order to complete.
We're using the shiny new Gradle build system. I'm wondering if I could do something like a test-only flavor or a subproject that depends on the parent APK to make it go. I tried making this work with a separate project altogether using the Robotium instructions for testing a source-less debug APK, but it didn't work. Maybe because I was on real hardware and not an emulator. I've had poor luck with the emulator, even with the hardware acceleration installed.
Any advice, or should I just hold my breath and roll with my builds requiring the integration server to be available when builds are happening?
According to their Maven instructions all you need to do is add robotium-solo as a compile dependency.
repositories {
mavenCentral()
}
dependencies {
instrumentTestCompile 'com.jayway.android.robotium:robotium-solo:4.2'
}
This will ensure you have the robotium-solo.jar file in your classpath. Then define your tests in the src/instrumentTest directory and run gradle build. See if that works?
I'll help where I can, as we converted from maven to gradle about a year ago.
*EDIT OP wanted the tests to run separately from a gradle build, so the solution is to specify a custom source set like so:
sourceSets {
integrationTest {
// Gives you access to the compiled classes in your tests
compileClasspath += main.output
runtimeClasspath += main.output
}
}
dependencies {
integrationTestCompile 'com.jayway.android.robotium:robotium-solo:4.2'
}
// To run the tests: ./gradlew integrationTest
task integrationTest(type: Test) {
testClassesDir = sourceSests.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath
}
Note: I don't have the android SDK installed on this computer. If main.output does not work try it with andriod.sourceSets.main.output and see if that works.