com.android.dex.DexException: Multiple dex files define Lorg/hamcrest/Description
occurring while trying to do a debug build/test either via Android Studio or via Gradle command-line on my application.
The release build (without tests) works fine but as soon as testing is included (hamcrest being a testing library), the build fails with the above error.
I've checked my module dependencies and there's no duplicate requirements which gradle -q dependencies corroborates.
Project settings.gradle
include ':[library module]'
include ':[main module]'
Project build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.9.+'
classpath 'org.robolectric.gradle:gradle-android-test-plugin:0.9.+'
}
}
allprojects {
repositories {
mavenCentral()
}
}
[library module] build.gradle
apply plugin: 'android-library'
android {
compileSdkVersion 19
buildToolsVersion "19.0.0"
defaultConfig {
minSdkVersion 14
targetSdkVersion 19
}
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
}
}
dependencies {
compile 'com.google.zxing:core:3.0.+'
compile 'com.bugsnag:bugsnag-android:2.1.1+'
}
[main module] build.gradle
apply plugin: 'android'
android {
signingConfigs {
release {
[...]
}
}
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
res.srcDirs = ['src/main/res']
}
androidTest {
setRoot('src/test')
}
instrumentTest {
}
}
compileSdkVersion 19
buildToolsVersion '19.0.0'
defaultConfig {
minSdkVersion 14
targetSdkVersion 19
testPackageName "[main.packageName].tests"
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
}
}
apply plugin: 'android-test'
androidTest {
// configure the set of classes for JUnit tests
include '**/*Test.class'
// configure max heap size of the test JVM
maxHeapSize = "2048m"
}
repositories {
maven { url 'https://repo.commonsware.com.s3.amazonaws.com' }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
dependencies {
androidTestCompile 'junit:junit:4.10'
androidTestCompile 'org.robolectric:robolectric:2.3-SNAPSHOT'
androidTestCompile 'com.squareup:fest-android:1.0.+'
compile project(':[library module]')
compile 'com.github.gabrielemariotti.changeloglib:library:1.4.+'
compile 'com.google.code.gson:gson:2.2.4'
compile 'com.google.android.gms:play-services:+'
compile 'com.android.support:appcompat-v7:+'
compile ('de.keyboardsurfer.android.widget:crouton:1.8.+') {
exclude group: 'com.google.android', module: 'support-v4'
}
compile files('libs/CWAC-LoaderEx.jar')
compile 'com.squareup.okhttp:okhttp:1.5.+'
compile 'com.octo.android.robospice:robospice:1.4.11'
compile 'com.octo.android.robospice:robospice-cache:1.4.11'
compile 'com.octo.android.robospice:robospice-retrofit:1.4.11'
compile 'com.commonsware.cwac:security:0.1.+'
compile 'com.readystatesoftware.sqliteasset:sqliteassethelper:+'
}
I solved the error by looking in Android Studio for the exact class called 'Description'. It turned out to be present in 3 jars. One from junit, one from a direct dependency and one from mockito.
It turns out that junit, instead of a normal dependency, includes the Hamcrest classes in the junit jar.
To be able to solve the problem include junit-dep instead of junit.
so change
androidTestCompile('junit:junit:4.8.+')
to
androidTestCompile('junit:junit-dep:4.8.+')
Mockito has the same problem/solution: use mockito-core.1.9.5.jar instead of mockito-all.1.9.5.jar
My project had a dependency on json-simple version 1.1.1, which for some reason has a run-time dependency on junit version 4.1.0, which itself has a dependency on Hamcrest. I could see this if I ran gradle dependencies or alternatively by inspecting the json-simple POM.xml.
// compile - Classpath for compiling the main sources.
\--- com.googlecode.json-simple:json-simple:1.1.1
\--- junit:junit:4.10
\--- org.hamcrest:hamcrest-core:1.1
Excluding the junit artifact from json-simple allowed me to build.
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile ('com.googlecode.json-simple:json-simple:1.1.1') {
exclude module: 'junit'
}
}
Robolectric 2.3 depends on JUnit 4.8.1 (version explicit). You're importing JUnit 4.10 (version explicit). Hamcrest is probably simply the first of many duplicates that dex is choking on - try changing your JUnit requirement version to 4.8+ (or excluding JUnit from the Robolectric dependency).
exclude module: junit
if you are using json:simple dependency
Related
I've cloned a github repository because I wanted to study the code, but when I tried to build it in Android Studio, I ran into some trouble.
After adding the google maven repository (as prompted by Android Studio) and updating both the Gradle Plugin Version and the Grade Version (to 3.5.2 and to 5.4.1, respectively), the build fails because of the following error:
Cause: duplicate entry: META-INF/MANIFEST.MF
And this, to be more specific:
Caused by: java.util.zip.ZipException: duplicate entry: META-INF/MANIFEST.MF
Here is my project level build.gradle file:
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
maven {
url 'https://maven.google.com'
}
}
}
Here's my module build.gradle file (before trying anything):
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion '28.0.3'
defaultConfig {
applicationId "com.thelittlenaruto.supportdesignexample"
minSdkVersion 11
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation ('com.android.support:appcompat-v7:22.2.1')
implementation ('com.android.support:design:22.2.1')
implementation 'com.github.frankiesardo:linearlistview:1.0.1#aar'
}
Here's what I've tried so far:
Adding the following to the android section of my module build.gradle file:
sourceSets {
main{
java{
exclude '**/META-INF/MANIFEST'
exclude '**/META-INF/MANIFEST.MF'
exclude 'META-INF/MANIFEST'
exclude 'META-INF/MANIFEST.MF'
exclude '!META-INF/MANIFEST.MF'
}
}
}
Adding this:
sourceSets.main.res.filter.exclude 'META-INF/MANIFEST'
sourceSets.main.res.filter.exclude 'META-INF/MANIFEST.MF'
Also this:
packagingOptions {
apply plugin: 'project-report'
exclude '**/META-INF/MANIFEST'
exclude '**/META-INF/MANIFEST.MF'
exclude 'META-INF/MANIFEST'
exclude 'META-INF/MANIFEST.MF'
exclude '!META-INF/MANIFEST.MF'
}
And this:
packagingOptions {
pickFirst '**/META-INF/MANIFEST'
pickFirst '**/META-INF/MANIFEST.MF'
pickFirst 'META-INF/MANIFEST'
pickFirst 'META-INF/MANIFEST.MF'
pickFirst '!META-INF/MANIFEST.MF'
}
This:
aaptOptions {
ignoreAssetsPattern "!META-INF/MANIFEST.MF"
ignoreAssetsPattern "META-INF/MANIFEST.MF"
}
I think I've tried mostly everything in this question:
How to exclude certain files from Android Studio gradle builds?
Nothing worked.
After searching for a solution, I think the problem is that I have duplicated dependencies. So I've tried the following:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation ('com.android.support:appcompat-v7:22.2.1'){
exclude module: 'support-v4'
}
implementation ('com.android.support:design:22.2.1')
implementation 'com.github.frankiesardo:linearlistview:1.0.1#aar'
}
And this:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation ('com.android.support:design:22.2.1'){
exclude module: 'support-v7'
}
implementation 'com.github.frankiesardo:linearlistview:1.0.1#aar'
}
I still get the same error.
What am I doing wrong?
As Rajen Raiyarela said, go to File->Project Structure->Project->Android Gradle Plugin Version and downgrade it from 3.5.2 to 3.5.1.
Set project dependencies to:
classpath 'com.android.tools.build:gradle:3.5.3'
or latest one.
Note: by doing this, my problem has been resolved.
This issue is happening because of duplicate dependencies.
Check for multiple dependencies in the Gradle app.
Either package it once or not at all:
android {
packagingOptions {
pickFirst "META-INF/MANIFEST.MF"
// exclude "META-INF/MANIFEST.MF"
}
}
as #rubo77 says and after my confirmation:
Latest solution
Upgrade gradle version
eg:
from 3.5.2 to 3.5.3
from 3.5.2 to 3.5.4
Obsolete solution:
downgrade from 3.5.2 to 3.5.1
my choice is : upgrade from 3.5.2 to 3.5.4
build.gradle:
dependencies {
// classpath 'com.android.tools.build:gradle:3.5.2'
// classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.android.tools.build:gradle:3.5.4'
}
I am working on an android app with GluonMobile. For one feature I need a ExoPlayer.
So I included the dependency com.google.android.exoplayer:exoplayer:+ .
It seems that the dependecy is an aar -file and InteliJ could not find any of ExoPlayers classes.
Here my buildscript:
buildscript {
repositories {
mavenCentral()
jcenter()
google()
maven {
url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
}
}
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:+'
classpath 'com.github.jengelman.gradle.plugins:shadow:+'
}
}
apply plugin: 'org.javafxports.jfxmobile'
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'java'
apply plugin: 'idea'
idea {
module {
downloadJavadoc = true
downloadSources = true
}
}
repositories {
mavenCentral()
jcenter()
google()
maven {
url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
}
maven {
url uri('libs')
}
}
mainClassName = '[...].main.Main'
version = '2.0_Alpha'
dependencies {
compile "com.gluonhq:charm:+"
compile "com.gluonhq:glisten-afterburner:+"
compile "com.google.apis:google-api-services-youtube:+"
compile "com.google.api-client:google-api-client-java6:+"
compile "com.google.oauth-client:google-oauth-client-jetty:+"
compile "com.google.code.gson:gson:+"
compileOnly 'lib.idea:annotations:0'
androidImplementation "org.javafxports:jfxdvk:+"
androidImplementation 'com.google.android.exoplayer:exoplayer:+#aar'
}
jfxmobile {
downConfig {
version = '+'
// Do not edit the line below. Use Gluon Mobile Settings in your project context menu instead
//noinspection GroovyAssignabilityCheck
plugins 'browser', 'display', 'lifecycle', 'statusbar', 'storage'
}
android {
manifest = 'src/android/AndroidManifest.xml'
//androidSdk = "${ANDROID_HOME}"
compileSdkVersion = 28
targetSdkVersion = 22
minSdkVersion = 16
packagingOptions {
exclude 'META-INF/DEPENDENCIES.txt'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/LICENSE'
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/notice.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/dependencies.txt'
exclude 'META-INF/LGPL2.1'
}
}
}
task installApk{
group = "gluon mobile for android"
doLast{
exec {
workingDir "${ANDROID_HOME}\\platform-tools"
commandLine "${workingDir}\\adb.exe", "install", "${buildDir}/javafxports/android/YouJavaTubeApp.apk"
}
}
}
I found already something about explodeAarDependencies(...) but it did not work. So have somebody any ideas how to include (any) aar dependencies to my GluonMobile project.
Thank you for your help.
You are on the right track about explodeAarDependencies, this is the task used by the jfxmobile plugin to unpack .aar dependencies into .jar and other resources.
You can find about the task here.
How to use it:
In your build.gradle file, include the dependency:
dependencies {
...
androidCompile 'com.google.android.exoplayer:exoplayer:2.9.0'
}
Note 1: don't to use #aar
Note 2: the jfxmobile plugin uses some defined configurations like androidCompile instead of androidImplementation.
Note 3: I'd rather use the given version, not +.
And at the end of the file, add the task:
project.afterEvaluate {
explodeAarDependencies(project.configurations.androidCompile)
}
And that's it.
Save and apply/sync/reload the build and you should see exoplayer and a bunch of transitive dependencies included into the Android compile dependencies, both .aar and .jar files.
I think you are adding dependencies in the wrong gradle file.
There will be 2 gradle files , One for project level and for app level. you need to add your libraries dependencies in app level gradle.
whereas you might be adding in the project level gradle.
My Gradle file looks like this :
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion "26.0.3"
defaultConfig {
applicationId "my.application.id"
minSdkVersion 16
targetSdkVersion 26
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.squareup.picasso:picasso:2.5.2'
implementation 'com.android.support:recyclerview-v7:26.1.0'
implementation 'com.google.android.exoplayer:exoplayer:2.9.0'
}
For more details on adding exoplayer pls refer to
Github and
https://developer.android.com/guide/topics/media/exoplayer
Im having a problems when trying to implement gcm. When I try to sync gradle files this error appears:
Warning:Gradle version 2.8 is required. Current version is 2.4. If using the gradle wrapper, try editing the distributionUrl in D:\MyProjects\Android\Enjoy\gradle\wrapper\gradle-wrapper.properties to gradle-2.8-all.zip
Tried to go to wrapper and change it to 2.8, but its still not working.
Here is my app build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "enjoy.enjoyprague_restaurants_bars"
minSdkVersion 17
targetSdkVersion 23
versionCode 1
versionName "1.0"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
}
dexOptions {
javaMaxHeapSize "4g"
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
// android libraries activity, design
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:design:23.1.1'
compile 'com.android.support:cardview-v7:23.1.1'
compile 'com.android.support:recyclerview-v7:23.1.1'
// application
compile 'com.android.support:multidex:1.0.1'
// volley for handlers
compile 'com.mcxiaoke.volley:library:1.0.19'
compile 'com.google.code.gson:gson:2.4'
// picasso
compile 'com.squareup.picasso:picasso:2.5.2'
// simple xml
compile('org.simpleframework:simple-xml:2.7.1') {
exclude group: 'stax', module: 'stax-api'
exclude group: 'xpp3', module: 'xpp3'
}
// floating action menu
compile 'com.oguzdev:CircularFloatingActionMenu:1.0.2'
// Google Map api
compile 'com.google.android.gms:play-services:8.4.0'
compile 'com.google.android.gms:play-services-gcm:8.4.0'
compile 'com.google.maps.android:android-maps-utils:0.4'
}
//google gcm sender
apply plugin: 'com.google.gms.google-services'
and top level build gradle:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.0.0-alpha3'
classpath 'com.google.gms:google-services:2.0.0-alpha3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
maven { url "http://dl.bintray.com/populov/maven" }
mavenCentral()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Open gradle folder in your project directory, and change gradle wrapper properties file. (you can find that last line indicating the path to gradle used in build). You may find it incorrect (e.g. http\://) fix it to (http://)
Ok, so, Android Studio is very buggy. Now, what you need to do is go to this question and do exactly as they said there. Take it to offline and that stuff. It will work, guaranteed.
https://stackoverflow.com/a/21996772/4458300
Use Graddle Wrapper
1)
Check distributionUrl and see if it is specified as gradle-2.8.zip at the Gradle-wrapper properties file within the Android project.
Project/gradle/wrapper/gradle-wrapper.properties
Run Gradle Wrapper at the top level of the project
Unix:
./gradlew wrapper
Windows:
gradlew.bat wrapper
Build with Gradle Wrapper.
Unix:
./gradlew build
Windows:
gradlew.bat build
Find in your project's structure in Android Studio this file
Open gradle-wrapper.properties and change this line:
distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
with
distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
It should work
I've been trying to do it for a few days, with no result. I need to set up Robolectric in Android Studio (0.8.9, latest version).
I followed different tutorials Android Unit and Integration testing, Roboelectric installation for Unit testing, Android Gradle app with Roboelectric, How to run Roboelectric JUnit tests but always got some kind of error.
So I created module specially for testing:
Kedzoh (Project) build.gradle:
// Top-level build file where you can add configuration options common to all sub- projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.12.+'
classpath 'org.robolectric:robolectric-gradle-plugin:0.12.+'
}
}
allprojects {
repositories {
jcenter()
}
}
app build.gradle:
apply plugin: 'com.android.application'
apply plugin: 'android'
android {
compileSdkVersion 19
buildToolsVersion '19.1.0'
defaultConfig {
applicationId 'com.dev.kedzoh'
minSdkVersion 9
targetSdkVersion 19
versionCode 14
versionName '1.6.7'
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:19.+'
compile 'com.google.android.gms:play-services:4.2.42'
compile 'com.squareup.retrofit:retrofit:1.6.1'
compile 'com.squareup.okhttp:okhttp:2.0.0'
compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'
compile 'com.google.code.gson:gson:2.2.4'
compile 'com.squareup.picasso:picasso:2.3.3'
// You must install or update the Support Repository through the SDK manager to use this dependency.
compile 'com.android.support:support-v4:19.+'
compile 'com.google.guava:guava:18.0-rc1'
compile 'com.sothree.slidinguppanel:library:+'
compile 'com.larswerkman:HoloColorPicker:1.4'
}
kedzoh-tests build.gradle:
apply plugin: 'java'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.squareup.retrofit:retrofit:1.6.1'
compile 'com.squareup.okhttp:okhttp:2.0.0'
compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'
compile 'com.google.code.gson:gson:2.2.4'
compile 'com.squareup.picasso:picasso:2.3.3'
// You must install or update the Support Repository through the SDK manager to use this dependency.
compile 'com.google.guava:guava:18.0-rc1'
compile 'com.sothree.slidinguppanel:library:+'
compile 'com.larswerkman:HoloColorPicker:1.4'
testCompile 'junit:junit:4.+'
testCompile 'org.robolectric:robolectric:2.2'
}
At this point I cannot import Robolectric classes, it gives me error. When I add apply plugin: 'robolectric' to kedzoh-tests build.gradle, it asks for 'android' plugin. After I add it, it complains there is no Manifest and fails to build.
I'm not sure that this is the right configuration, since it never worked really. Could anyone give some advice how to set Robolectric in Android Studio, please?
EDIT:
I tried the answer below, but still stuck with "Class not found" error:
There already different project templates for robolectric. Did you try https://github.com/nenick/android-gradle-template ?
I think you maybe making your life more difficult and complicated by creating your test module outside of the main 'app' module. Most of the tutorials I have seen have an androidTest folder in the app module that can contain your Robolectric tests. All of the older tutorials based around Eclipse I have seen, seem to instruct us to create test modules separate to the main project.
If I were using Robolectric I would setup the project like I have created for you https://github.com/marcthomas2013/Kedzoh. I would use the androidTest folder to put my tests and configure the gradle files as follows.
Note that the dependencies for the tests are included using the androidTestCompile declaration and application dependencies are declared using just compile.
Another item in this gradle file is the robolectric section where it is including and excluding classes in the androidTest folder. Anything that isn't in the espresso folder will be run using the gradlew test target and everything including the espresso folder will be run when calling gradlew connectedAndroidTest target.
app gradle file
apply plugin: 'com.android.application'
apply plugin: 'robolectric'
android {
packagingOptions {
exclude 'LICENSE.txt'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE'
}
compileSdkVersion 19
buildToolsVersion "19.1.0"
defaultConfig {
minSdkVersion 18
targetSdkVersion 18
versionCode 2
versionName "1.0.0-SNAPSHOT"
testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner"
}
buildTypes {
release {
runProguard false
}
}
sourceSets {
androidTest {
setRoot('src/androidTest')
}
}
}
robolectric {
include '**/*Test.class'
exclude '**/espresso/**/*.class'
}
dependencies {
repositories {
mavenCentral()
}
compile 'com.sothree.slidinguppanel:library:2.0.1'
androidTestCompile('junit:junit:4.11') {
exclude module: 'hamcrest-core'
}
// Espresso
androidTestCompile files('libs/espresso-1.1.jar')
androidTestCompile files('libs/testrunner-1.1.jar')
androidTestCompile files('libs/testrunner-runtime-1.1.jar')
androidTestCompile 'com.google.guava:guava:14.0.1'
androidTestCompile 'com.squareup.dagger:dagger:1.1.0'
androidTestCompile 'org.hamcrest:hamcrest-integration:1.1'
androidTestCompile 'org.hamcrest:hamcrest-core:1.1'
androidTestCompile 'org.hamcrest:hamcrest-library:1.1'
androidTestCompile('org.robolectric:robolectric:2.3') {
exclude module: 'classworlds'
exclude module: 'commons-logging'
exclude module: 'httpclient'
exclude module: 'maven-artifact'
exclude module: 'maven-artifact-manager'
exclude module: 'maven-error-diagnostics'
exclude module: 'maven-model'
exclude module: 'maven-project'
exclude module: 'maven-settings'
exclude module: 'plexus-container-default'
exclude module: 'plexus-interpolation'
exclude module: 'plexus-utils'
exclude module: 'wagon-file'
exclude module: 'wagon-http-lightweight'
exclude module: 'wagon-provider-api'
}
androidTestCompile 'com.squareup:fest-android:1.0.+'
}
project build file
Here we include the robolectric class path so that we can use the robolectric gradle commands in the config file above.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.12.2'
classpath 'org.robolectric:robolectric-gradle-plugin:0.11.+'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
mavenCentral()
}
}
Can you explain what errors that you are having as there could be many possible errors based on how you are working, also is there a particular reason for creating a separate test module.
The project that I have provided is based on the deck-gradle setup (https://github.com/robolectric/deckard-gradle) there are a number of tips in here about JUnit conflicts etc. that you could be having trouble with.
Once you have got this far in order to be able to debug the unit test in the application you will have to manually tweak the classpath when launching the test (Not Pretty at all!), based on the information in this article https://github.com/codepath/android_guides/wiki/Robolectric-Installation-for-Unit-Testing
You will need to run your unit test, wait for it to fail, copy the -classpath parameter and it's value (It will be quite long and starts and finishes with ") and copy this into your VM Options in your run configuration, then at the end of that classpath add a ; or a : depending on your OS path delimeter and add the path to your test classes which will be something like <ABSOLUTE_PATH_TO_PROJECT>/build/test-classes this will add your test classes to the class path and then Android Studio should be able to run them.
This is also assuming that the steps to run the gradle testClasses has been done from the article http://blog.blundell-apps.com/how-to-run-robolectric-junit-tests-in-android-studio/
I'm trying to use Robolectric in a project build with gradle inside the new Ide for android: Android studio, but I'm facing a strange problem, I've correctly imported all the libraries and created the "test" folder inside "src", the fact is that whenever I run the tests the ide keep saying "Class not found: "com.example.myandroidproject.test" what I'm doing wrong? i need to change something in the gradle.build? here's my directory structure:
#Aldo Borrero, finally it seems that someone has found the way to test android projects under "Android Studio" using Robolectric and Gradle.
Please, take a look at this answer Robolectric with Gradle
Update:
The guys from square have released a plugin to make Robolectric work out of the box with Gradle and Android Studio, this feature will be integrated with Robolectric in v2, meanwhile you can grab the plugin here: Gradle Android test Plugin
I tried different appraoaches to combine android studio & robolectric & espresso. I ended with this example project setup https://github.com/nenick/android-gradle-template
Here some explanation for the different approaches:
application module + espresso + robolectric
There is an example https://github.com/robolectric/deckard-gradle supported by robolectric maintainers.
This is based on the plugin https://github.com/robolectric/gradle-android-test-plugin. But this have a drawback with dependency pollution reported at https://github.com/robolectric/gradle-android-test-plugin/issues/17 which results in slow esspresso tests compile time and execution time.
build.gradle snippet which combines all
buildscript {
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.10.+'
classpath 'org.robolectric.gradle:gradle-android-test-plugin:0.10.+'
}
}
apply plugin: 'android'
apply plugin: 'android-test'
android {
defaultConfig {
testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner"
}
}
androidTest {
include '**/*Test.class'
exclude '**/espresso/**/*.class'
}
dependencies {
androidTestCompile('junit:junit:4.11')
androidTestCompile('org.robolectric:robolectric:2.3-SNAPSHOT')
androidTestCompile 'com.jakewharton.espresso:espresso:1.1-r2'
}
seperate espresso
An example is shown by https://github.com/stephanenicolas/Quality-Tools-for-Android but it is much outdated and had also some drawbacks. It will recompile
and makes android studio behave strange. It flags application module sources as (root source) of the espresso test module. That works but not intuitive.
build.gradle snippet for espresso module
dependencies {
androidTestCompile 'com.jakewharton.espresso:espresso:1.1-r2'
}
android {
sourceSets {
main {
manifest.srcFile '../AndroidSample/AndroidManifest.xml'
java.srcDirs += ['../AndroidSample/src/main/java']
resources.srcDirs = ['../AndroidSample/res']
res.srcDirs = ['../AndroidSample/res']
}
}
defaultConfig {
testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner"
}
}
spereate robolectric
There exist a plugin https://github.com/novoda/gradle-android-test-plugin which enable us to put robolectric tests in a sperate package. This project
setup works for me great:
- MyProject
|- app (with espresso tests)
|- - build.gradle (app)
|- robolectric (unit tests)
|- - build.gradle (robo)
build.gradle (app + espresso) snippet
dependencies {
androidTestCompile 'com.jakewharton.espresso:espresso:1.1-r2'
}
android {
defaultConfig {
testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner"
}
}
build.gradle (robo) snippet
buildscript {
repositories {
mavenCentral()
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:0.9.+'
classpath "com.novoda:gradle-android-test-plugin:0.9.8-SNAPSHOT"
}
}
android {
projectUnderTest ':AndroidSample'
}
apply plugin: 'java'
apply plugin: 'android-test'
dependencies {
testCompile 'junit:junit:4.11'
testCompile 'org.mockito:mockito-core:1.9.5'
testCompile 'com.squareup:fest-android:1.0.+')
testCompile ('org.robolectric:robolectric:2.3-SNAPSHOT')
}
There a some pitfall when you try setup this project setup, so just start with a working example: https://github.com/nenick/android-gradle-template
This is unlikely to work out of the box as src/test isn't used automatically.
You'd need to create a test task automatically that compiles this source sets, sets the right dependencies and run it.
We intend to support this in the future but right now you'd need to do this manually.
I tested all the solutions presented here and they all lack of something (version of gradle / gradle plugin not supported, library project not supported, no integration with Android studio, etc). It may not be true in the future but it is today.
The best way I found is to configure the unit tests by yourself. You will need to add a few lines of config to your build.gradle file. Explications are on the following article: http://tryge.com/2013/02/28/android-gradle-build/. Since I'm not the author, I don't think I can copy past the content here directly.
In addition to that article, if you want configure Android Studio to see the unit test folder as a source folder (autocompletion and stuff), you can apply the following little dirty hack and let the IDE think that the unit tests are located in the instrumentationTest folder. Of course, it will mess with your real instrumentation tests so it works only if you don't have any of those.
build.gradle
// the unit test source set as described in the article
sourceSets {
unitTest {
java.srcDir file('src/test/java')
resources.srcDir file('src/test/resources')
}
}
android {
// tell Android studio that the instrumentTest source set is located in the unit test source set
sourceSets {
instrumentTest.setRoot('src/test')
}
}
dependencies {
// your unit test dependencies as described in the article
unitTestCompile files("$project.buildDir/classes/release")
unitTestCompile 'junit:junit:4.11'
unitTestCompile 'com.google.android:android:4.1.1.4'
unitTestCompile 'org.robolectric:robolectric:2.1.1'
// duplicate these dependencies in the instrumentTestCompile scope
// in order to have the integration in Android Studio (autocompletion and stuff)
instrumentTestCompile 'junit:junit:4.11'
instrumentTestCompile 'org.robolectric:robolectric:2.1.1'
}
// the rest of the config as described in the article
Tested with Android Studio 0.2.6 and android gradle plugin 0.5.
Gradle Android Unit Testing Plugin is the best option for me.
Developed by Jake Wharton, I guess it is going to be the next standard (maybe until google releases an out of the box support for Robolectric in Android Studio).
You can import the library by adding in your build.gradle file:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.X.+'
classpath 'com.squareup.gradle:gradle-android-test-plugin:0.9.+'
}
}
...
apply plugin: 'android-test'
...
dependencies {
testCompile 'junit:junit:4.10'
testCompile 'org.robolectric:robolectric:2.1.+'
testCompile 'com.squareup:fest-android:1.0.+'
}
Update: This library has been deprecated since gradle plugin version 0.8
I've tested a lot of scenarios (like http://tryge.com/2013/02/28/android-gradle-build/ and http://www.peterfriese.de/android-testing-with-robolectric/) but only the solution provided by the Robolectric team worked for me. The setup uses instrumented and robolectric tests in one Android project with gradle as build system.
See http://robolectric.org/getting_started/
and the sources on
https://github.com/robolectric/deckard-gradle
buildscript {
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.9.2'
classpath 'org.robolectric.gradle:gradle-android-test-plugin:0.9.4'
}
}
allprojects {
repositories {
mavenCentral()
}
}
apply plugin: 'android'
apply plugin: 'android-test'
android {
packagingOptions {
exclude 'LICENSE.txt'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE'
}
compileSdkVersion 19
buildToolsVersion "19.0.3"
defaultConfig {
minSdkVersion 18
targetSdkVersion 18
versionCode 2
versionName "1.0.0-SNAPSHOT"
testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner"
}
buildTypes {
release {
runProguard false
}
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
res.srcDirs = ['res']
}
androidTest {
setRoot('src/test')
}
}
}
androidTest {
include '**/*Test.class'
exclude '**/espresso/**/*.class'
}
dependencies {
repositories {
mavenCentral()
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots/'
}
}
// Espresso
androidTestCompile files('lib/espresso-1.1.jar', 'lib/testrunner-1.1.jar', 'lib/testrunner-runtime-1.1.jar')
androidTestCompile 'com.google.guava:guava:14.0.1',
'com.squareup.dagger:dagger:1.1.0',
'org.hamcrest:hamcrest-integration:1.1',
'org.hamcrest:hamcrest-core:1.1',
'org.hamcrest:hamcrest-library:1.1'
androidTestCompile('junit:junit:4.11') {
exclude module: 'hamcrest-core'
}
androidTestCompile('org.robolectric:robolectric:2.3-SNAPSHOT') {
exclude module: 'classworlds'
exclude module: 'maven-artifact'
exclude module: 'maven-artifact-manager'
exclude module: 'maven-error-diagnostics'
exclude module: 'maven-model'
exclude module: 'maven-plugin-registry'
exclude module: 'maven-profile'
exclude module: 'maven-project'
exclude module: 'maven-settings'
exclude module: 'nekohtml'
exclude module: 'plexus-container-default'
exclude module: 'plexus-interpolation'
exclude module: 'plexus-utils'
exclude module: 'wagon-file'
exclude module: 'wagon-http-lightweight'
exclude module: 'wagon-http-shared'
exclude module: 'wagon-provider-api'
}
androidTestCompile 'com.squareup:fest-android:1.0.+'
}
apply plugin: 'idea'
idea {
module {
testOutputDir = file('build/test-classes/debug')
}
}