13

I have an Android project (generated by Cordova) that I want to add (instrumentation) tests to. It has only one MainActivity.java that should be tested.

Normally this means adding some dependencies to build.gradle and creating a file /src/androidTest/java/org/example/package/MainActivityTest.java with an MainActivityTest class and some test methods. (In Android Studio I can even generate those by using Run -> "Record Espresso Test" - so really simple and works).

Unfortunately, I now have the requirement that those test files do actually live outside the project directory. There should be only minimal changes on the existing Cordova project (as it is regenerated and handled as a build artifact). The MainActivity.java would best be in the same root folder where the Android project is in /android.

How can I achieve that?


The build.gradle changes can be added to a build-extras.gradle file that the real build.gradle already includes, so this is taken care of.

But I have no idea how to place the MainActivityTest.java outside of the project folder structure and still be able run it inside the project.

For iOS you can link external files into the project with absolute paths. Something like that would be perfect here as well.

I looked at sourceSets but I am not sure how to integrate this in the Cordova Android project which already has this non default (I think?) sourceSets:

android {
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
            jniLibs.srcDirs = ['libs']
        }
    }
    ...
}     
janpio
  • 10,645
  • 16
  • 64
  • 107

1 Answers1

9

There are two ways:

  1. You can create independent Android project (which you can put at any folder outside the app project) for your instrumentation tests only using Android Studio 3.0. For this purpose I used:

    Android Studio 3.0 Beta 6

    Android Gradle Plugin: 'com.android.tools.build:gradle:3.0.0-beta6'

  2. You can create a separate module (which you can put at any folder outside the app project) for your instrumentation tests. For this you can use:

    With Android Studio 3.0.0

    With Android Gradle Plugin 3.0.0

    With Gradle Wrapper 4.2.1-all

    If you receive an error that the AndroidManifest of the instrumentation-test-module and the app-module cannot be merged, you might be limited to old Gradle versions which

    Tested with Android Studio 2.3.3 and 3.0.0

    The highest Android Gradle Plugin will be 2.2.3

    Gradle Wrapper 3.3-all (or 3.4.1 / 4.2.1)

    Note: This is broken for Android Gradle Plugin 2.3.0!

I created SAMPLE PROJECT to demonstrate structure of tests in both cases.


The build.gradle of the project/module has to use this plugin:

// A plugin used for test-only-modules
apply plugin: 'com.android.test'

This plugin uses TestExtension (link to its DSL). With TestExtension and 'com.android.test' plugin your gradle file will look like:

apply plugin: 'com.android.test'

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.2"
    defaultConfig {
        minSdkVersion 9
        targetSdkVersion 26

        // The package name of the test app
        testApplicationId 'com.example.android.testing.espresso.BasicSample.tests'
        // The Instrumentation test runner used to run tests.
        testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
    }
    // Set the target app project. The module specified here should contain the production code
    // test should run against.
    targetProjectPath ':app'
}

dependencies {
    // Testing-only dependencies
    // Force usage of support annotations in the test app, since it is internally used by the runner module.
    compile 'junit:junit:4.12'
    compile 'com.android.support:support-annotations:25.4.0'
    compile 'com.android.support.test:runner:1.0.1'
    compile 'com.android.support.test:rules:1.0.1'
    compile 'com.android.support.test.espresso:espresso-core:3.0.1'
}

Pay attention that here no "androidTestCompile" is supported!

Do not forget to create AndroidManifest.xml. It will look like:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.example.android.testing.espresso.BasicSample.tests">

<!-- Specify runner and target application package -->
<instrumentation
    android:name="android.support.test.runner.AndroidJUnitRunner"
    android:functionalTest="false"
    android:handleProfiling="false"
    android:label="Tests for com.example.android.testing.espresso.BasicSample"
    android:targetPackage="com.example.android.testing.espresso.BasicSample"/>

    <application>
        <uses-library android:name="android.test.runner" />
    </application>

</manifest>

Pay attention that test source files are in "main" folder (not androidTest):

src->main->java->package.name.folders

Then you can link this test project to your application project in settings.gradle:

include ':module-androidTest'
project(':module-androidTest').projectDir = new File("../BasicSampleTests/test")

In Android Studio you must create "Android Instrumented Tests" run configuration. It will look like: enter image description here Now run your tests:

enter image description here

If you have build issues with product flavors then you should add publishNonDefault in build.gradle of your application:

android {
    ...
    defaultConfig {
       ...
    }
    publishNonDefault true
}
hb0
  • 3,350
  • 3
  • 30
  • 48
Sheikh
  • 1,116
  • 6
  • 15
  • Thanks, not specific to Cordova is totally fine - the Android project should be a _real_ Android project, so this should work. I will look into it and report back. – janpio Sep 27 '17 at 15:14
  • @janpio, please pay attention to these [google samples](https://github.com/googlesamples/android-testing-templates/tree/master/AndroidTestingBlueprint). – Sheikh Sep 27 '17 at 15:59
  • I did, can't get it to work. Reading this it all makes sense, but I get the strangest Gradle errors, even with a newly created super simple project. Also found no project with a working example :( – janpio Oct 02 '17 at 22:48
  • Tiny progress: The `android-testing-templates` sample from Google works now. As soon as I try it on a project without "flavors" it fails though :/ Studio = "The current project can not be run" and `.gradlew`= "Failed to finalize session : INSTALL_FAILED_VERSION_DOWNGRADE" – janpio Oct 03 '17 at 00:43
  • 1
    hi, @janpio, i rewrited my answer. Also I created simple sample project and added link to it. BTW i also had a lot of build issues and issues with Run configurations. So i had to move to Android Studio 3.0 Beta 6. My sample works perfectly there. – Sheikh Oct 03 '17 at 08:44
  • Wow @Sheihk, that is awesome - thanks. Good to hear it was not my stupidness causing the issues. I will see if I can get it to work, I will be a bit limited re the gradle version because of the Cordova project - but first to get it working in any way. – janpio Oct 03 '17 at 09:25
  • Yay, your sample project worked. Unfortunately I can't rely on Studio 3, so I will have to look into the Google sample again or see if I can get yours working with current tooling. Step by step... – janpio Oct 03 '17 at 11:09
  • I iterated on [your sample project](https://github.com/dsheikherev/separate_test_module) a bit: 1. I simplified it a bit by making the `BasicSampleTests` just a module instead of a (unused) project: https://github.com/janpio/separate_test_module/tree/simplify 2. to understand how your project compares to the [Android Sample](https://github.com/googlesamples/android-testing-templates/) I inlined the module into the main project: https://github.com/janpio/separate_test_module/tree/inline Now it is quite similar to the sample but for the Gradle version and BuildType/Flavor configuration. – janpio Oct 03 '17 at 19:55
  • Oh wow, I think I got it to work with the same (Gradle) versions as the android-testing-sample project: https://github.com/janpio/separate_test_module/tree/older-gradle – janpio Oct 03 '17 at 21:53
  • And tadaa, it also works if the testmodule is extracted outside of the project structure: https://github.com/janpio/separate_test_module/tree/old-gradle-extracted Now, what exactly did we both do wrong before? No idea. – janpio Oct 03 '17 at 22:04
  • 1
    Great job! We got that 2.2.1 version of the plug-in works. Now we need to find version which is the closest to latest 2.3.3 and which still works successful. – Sheikh Oct 04 '17 at 00:11
  • 2
    @janpio, okey, i finally figured it out. Tests as an independent project will work in Android Studio 3.0(with Andorid Gradle Plugin 3.0.0-betaX and gradle wrapper 4.1-all). Tests as a separate module(your variant in https://github.com/janpio/separate_test_module/tree/old-gradle-extracted) will work with Android Studio 2.3.3(with Andorid Gradle Plugin 2.2.3 and gradle wrapper 3.3-all). So the highest Plugin is 2.2.3 (from 2.3.0+ this functionality is broken). Does it fit your needs in your project? I think now when all is clear, we can close your question. – Sheikh Oct 04 '17 at 04:26
  • Did you test all the gradle versions or how did you find out since when it was broken? – janpio Oct 04 '17 at 21:16
  • 1
    Thanks! Yeah, i tried all from 2.2.1 to the current latest stable 2.3.3 :) i didn't try all versions of 3.0.0 because it matters to try it when it will be officially stable. So just used the latest for now 3.0.0-beta6 – Sheikh Oct 05 '17 at 03:27
  • I created this new question to maybe figure out what is causing it to fail for 2.2.x: https://stackoverflow.com/q/46590084/252627 – janpio Oct 05 '17 at 16:00
  • The SAMPLE PROJECT is EMPTY. – Xyldrun Jacob Dec 24 '19 at 08:58
  • @XyldrunJacob, no, the SAMPLE PROJECT is divided into few branches. But I haven't updated this project for quite long, so I think you will face build errors. – Sheikh Dec 25 '19 at 15:21
  • I tried this with the separate module approach and got error `INSTALL_FAILED_MISSING_SHARED_LIBRARY` when installing. Anyone else ran into this? – Sam Jun 27 '20 at 23:52