Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Double Espresso not working with Robolectric

I'm trying to run Espresso (using Double Espresso) via instrumentation testing and unit tests via Robolectric. What I have so far is largely based on the deckard-gradle example.

Note: Gradle 1.10

buildscript {
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath 'com.android.tools.build:gradle:0.10.4'
    classpath 'org.robolectric.gradle:gradle-android-test-plugin:0.10.0'
  }
}

apply plugin: 'android'
apply plugin: 'android-test'

android {
  compileSdkVersion 19
  buildToolsVersion '19.0.3'

  defaultConfig {
    packageName = 'com.example.app'
    minSdkVersion 9
    targetSdkVersion 19
    versionCode 1
    versionName '1.0.0'
    testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner"
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
  }

  buildTypes {
    debug {
      debuggable = true
      runProguard = false
    }

    release {
      debuggable = false
      runProguard = true
    }
  }

  sourceSets {
    androidTest {
      setRoot('src/test')
    }
  }

  packagingOptions {
    exclude 'LICENSE.txt'
  }
}

androidTest {
  include '**/*Test.class'
  exclude '**/espresso/**/*.class'
  maxHeapSize = "2048m"
}

repositories {
  mavenCentral()
}

dependencies {
  compile 'com.android.support:support-v4:19.1.0'

  androidTestCompile('com.jakewharton.espresso:espresso:1.1-r3')
  androidTestCompile('com.jakewharton.espresso:espresso-support-v4:1.1-r3') {
    exclude group: 'com.android.support', module: 'support-v4'
  }

  androidTestCompile('junit:junit:4.11') {
    exclude module: 'hamcrest-core'
  }
  androidTestCompile('org.robolectric:robolectric:2.3') {
    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.8'
}

My directory structure is as follows, where com.example.app.espresso needs to be run as connectedAndroidTest and com.example.app.data as test:

src
|- debug
|- main
|- release
|- test
   |- java
      |- com
         |- example
            |- app
               |- espresso
                  |- HomeActivityTest.java
               |- data
                  |- DataTest.java
   |- resources
      |- data_input.json

So when I run gradle clean test, I get errors not recognizing Espresso imports in HomeActivityTest.java.

When I run gradle clean connectedAndroidTest, I get errors not recognizing JUnit4 annotations in DataTest.java (FailedToCreateTests.testSuiteConstructionFailed).

If I take either part out (dependencies and sources), the other one works fine independently but not with everything included together.

Note: I tried importing Espresso jar's locally (no Double Espresso), same way deckard-gradle does it, which works until I use anything from the support-v4 library in the Espresso test (com.jakewharton.espresso:espresso-support-v4 appears to solve that, which there is no alternative for with local jar's), then it explodes into FailedToCreateTests.testSuiteConstructionFailed.

Has anyone got this structure working? Is there any way to exclude source paths from each target?

Any solutions (full or partial) would be appreciated.

like image 987
Mike Gouline Avatar asked Jun 02 '14 07:06

Mike Gouline


2 Answers

This is occurring because the Double Espresso artifacts are distributed as .aar files and the compile task that Robolectric generates for running the tests does not depend upon a task that unpackages .aar files that are part of the androidTestCompile dependency configuration.

Since you typically won't run your espresso tests as part of the task that runs your unit tests, you can safely exclude the espresso tests from the compilation task generated by the Robolectric plugin. I do this by adding a dependency to the compilation task generated by the Robolectric plugin to my build.gradle that touches up the source property. Example code below. Make sure to touch up the name of the robolectric generated compile task ('compileTestDebugJava' in my example) and your 'exclude' for your espresso tests as necessary.

tasks.whenTaskAdded { theTask ->
    if ("compileTestDebugJava".toString().equals(theTask.name.toString())) {
        def cleanupTask = "touchUpRobolectricSourceSet"
        project.task(cleanupTask) << {
            FileTree tree = fileTree(dir: 'src/test/java')
            tree.exclude '**/espresso/**/*.java'

            theTask.source = tree
        }
        theTask.dependsOn(cleanupTask)
    }
}
like image 109
jdonmoyer Avatar answered Oct 18 '22 22:10

jdonmoyer


Eventually, I abandoned the idea of using Double Espresso and going with the approach that deckard-gradle takes - manually importing the Espresso jar's (espresso, testrunner and testrunner-runtime).

It appears that either Double Espresso is doing more than just wrapping the jar's as aar's and hosting them or the fact that they are aar's causes problems. Would be interested to know why.

To avoid keeping local dependencies, I uploaded the Espresso jar's to a Maven repo, daisy-chained them (espresso depends on testrunner-runtime, testrunner-runner depends on testrunner) and included all the third-party dependencies (Guava, Hamcrest, Dagger etc) in the POM. If you don't have a hosted Maven repo, you can use GitHub as your repo: https://stackoverflow.com/a/14013645/818393.

Admittedly, not the best solution but it works.

like image 34
Mike Gouline Avatar answered Oct 18 '22 23:10

Mike Gouline