18

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:

enter image description here

luiges90
  • 4,493
  • 2
  • 28
  • 43
Flying Mongoose
  • 193
  • 1
  • 1
  • 7

6 Answers6

16

@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

Community
  • 1
  • 1
Imanol
  • 4,824
  • 2
  • 28
  • 35
7

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

nenick
  • 7,340
  • 3
  • 31
  • 23
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – bjb568 May 09 '14 at 06:26
  • An example snippet would be nice. – bjb568 May 15 '14 at 07:05
  • More reasons while you down vote this answer? And why you don't remove the other posts here with just links and a short sentence? – nenick May 16 '14 at 16:47
  • I didn't downvote. I just flagged the other link-only answers. – bjb568 May 16 '14 at 17:06
  • Then I judged to fast, sorry for that. – nenick May 16 '14 at 20:24
5

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.

Xavier Ducrohet
  • 28,383
  • 5
  • 88
  • 64
  • I'm having a similar problem, with the difference being that all my unit tests are in a separate Gradle project. The tests run fine on the command line when running gradle test on the parent, however, from within Android Studio, I also get "ClassNotFound" on the test case class. I noticed that Android Studio seems to simply execute Gradle under the hood, so why would that not work? – mxk Jun 11 '13 at 20:42
  • 3
    @Xav : any example on how to create such a task? Also, once the task is created, should we add it as a dependency on "check"? Thank you – LocoMike Jun 19 '13 at 14:41
  • I was able a while back to get Robolectric tests to run from a custom task in Android Studio (and it can already work in Gradle... see http://stackoverflow.com/questions/16649397/robolectric-with-gradle-resources-not-found ). You have to manipulate the module dependencies and setup quite a bit. However I never really published the steps anywhere because it wasn't practical, the android Gradle plugin will wipe out your customizations the next time it re-imports (soon). – derekv Aug 10 '13 at 14:45
3

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.

lukasz
  • 3,121
  • 1
  • 21
  • 20
2

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

Thomas Kaliakos
  • 3,274
  • 4
  • 25
  • 39
  • It's far from being the next standard, lot of things are not supported or not working well yet (library projects, integration with AS, etc). Right now using robolectric with gradle is just a pain in the ass. – lukasz Sep 01 '13 at 17:02
  • I actually found a way that works better for me, see my answer below. – lukasz Sep 01 '13 at 22:55
1

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')
    }
}
userM1433372
  • 5,345
  • 35
  • 38