読者です 読者をやめる 読者になる 読者になる

ほげほげ(仮)

仮死状態

Android StudioでRobolectricを使う

Android

※追記

JakeWharton / gradle-android-test-plugin がDEPRECATEDになってしまいました… なのでこの記事は参考にしないでください。記事自体は一応残しておきます。

※さらに追記

新しく書き直しました。AndroidStudio + Robolectric + Guardによる自動実行 - ほげほげ(仮)

Android StudioでRobolectricを使う手順のメモです。

JakeWharton / gradle-android-test-plugin を使用しますが、READMEが分かりにくかったのまとめました。

注意

  • とりあえず動くところまでしか確認していません。
  • この記事はすぐ古くなる気がします。最新の情報を確認してください。

プロジェクト作成

Android Studioで普通につくってください

テストディレクトリ作成

src/test/java を作成します。ここにテストコードを書いていきます。

build.gradle

テストディレクトリを指定

sourceSetsを追加します。

android {

    ....

    sourceSets {
        instrumentTest.setRoot('src/test')
    }
}

リポジトリ追加とプラグイン依存を追加

buildscriptrepositoriesリポジトリを追加して、プラグイン依存を追加します。

mavenCentralのだと少し古いっぽくて実行時にエラーになってしまいます。(すいません、詳しくは理解できてないです。まだmavenリポジトリに反映されてない感じなのかな??)
https://github.com/JakeWharton/gradle-android-test-plugin/pull/26

あと、Robolectricもバグがあるらしく2.2だと実行時にエラーになってしまうので、2.3-SNAPSHOTを使うようにするためリポジトリを追加します。
https://github.com/JakeWharton/gradle-android-test-plugin/issues/45

buildscript {
    repositories {
        mavenCentral()
        // ココ
        maven {
            url 'https://oss.sonatype.org/content/repositories/snapshots/'
        }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.7.+'
        // ココ
        classpath 'com.squareup.gradle:gradle-android-test-plugin:0.9.1-SNAPSHOT'
    }
}

repositories {
    mavenCentral()
    // ココ
    maven {
        url 'https://oss.sonatype.org/content/repositories/snapshots/'
    }
}

プラグイン追加

apply plugin: 'android-test'

必要なライブラリ依存を追加

testCompileinstrumentTestCompileに追加します。

Gradleから実行するにはtestCompileだけでも良いのですが、Android Studioが認識してくれないのか補完が効かないのでinstrumentTestCompileにも記述します。

dependencies {
    compile 'com.android.support:appcompat-v7:+'

    testCompile 'junit:junit:4.10'
    testCompile 'org.robolectric:robolectric:2.3-SNAPSHOT'

    instrumentTestCompile 'junit:junit:4.10'
    instrumentTestCompile 'org.robolectric:robolectric:2.3-SNAPSHOT'
}

targetSdkVersionを18にする

これを書いてる現時点ではRobolectricがAPI19をサポートしてなくて実行時にRobolectric does not support API level 19, sorry!っていうエラーになるので18にします。そのうち対応してくれるでしょう…

android {
    ...
    defaultConfig {
        minSdkVersion 7
        targetSdkVersion 18
        versionCode 1
        versionName "1.0"
    }
    ...
}

最終的なbuild.gradle

buildscript {
    repositories {
        mavenCentral()
        maven {
            url 'https://oss.sonatype.org/content/repositories/snapshots/'
        }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.7.+'
        classpath 'com.squareup.gradle:gradle-android-test-plugin:0.9.1-SNAPSHOT'
    }
}
apply plugin: 'android'
apply plugin: 'android-test'

repositories {
    mavenCentral()
    maven {
        url 'https://oss.sonatype.org/content/repositories/snapshots/'
    }
}

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.0"

    defaultConfig {
        minSdkVersion 7
        targetSdkVersion 18
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
    sourceSets {
        instrumentTest.setRoot('src/test')
    }
}

dependencies {
    compile 'com.android.support:appcompat-v7:+'

    testCompile 'junit:junit:4.10'
    testCompile 'org.robolectric:robolectric:2.3-SNAPSHOT'

    instrumentTestCompile 'junit:junit:4.10'
    instrumentTestCompile 'org.robolectric:robolectric:2.3-SNAPSHOT'
}

ここまで記述したらTool->Android->Sync Project with Grale Filesを実行して設定を反映させます。

TestRunnerのカスタマイズ

src/test/javaにパッケージを追加してそこに以下のクラスを作成します。

RobolectricがAndroidManifest.xmlを見つけられないみたいなので次のようにカスタマイズします。 実際にはgradle-android-test-pluginがSystemプロパティに設定してくれているようです。

import org.junit.runners.model.InitializationError;
import org.robolectric.AndroidManifest;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.res.Fs;

public class RobolectricGradleTestRunner extends RobolectricTestRunner {
    public RobolectricGradleTestRunner(Class<?> testClass) throws InitializationError {
        super(testClass);
    }

    @Override protected AndroidManifest getAppManifest(Config config) {
        String manifestProperty = System.getProperty("android.manifest");
        if (config.manifest().equals(Config.DEFAULT) && manifestProperty != null) {
            String resProperty = System.getProperty("android.resources");
            String assetsProperty = System.getProperty("android.assets");
            return new AndroidManifest(Fs.fileFromPath(manifestProperty), Fs.fileFromPath(resProperty),
                    Fs.fileFromPath(assetsProperty));
        }
        return super.getAppManifest(config);
    }
}

ここまでで準備は完了です。

テストを実行してみる

テスト対象クラス

てきとーにActivityにメソッドを追加します。

public class MainActivity extends ActionBarActivity {

    ...

    public String getMessage() {
        return "Hello World!";
    }
}

テストクラス

さっきのメソッドの戻り値をテストしてみます。TestRunnerはさっきカスタマイズしたクラスを使います。

import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;

@RunWith(RobolectricGradleTestRunner.class)
public class MainActivityTest {

    @Test
    public void testGetMessage() {
        MainActivity activity = Robolectric.buildActivity(MainActivity.class).create().get();
        assertThat(activity.getMessage(), equalTo("Hello World!"));
    }
}

テスト実行

ターミナルから実行します。

$ ./gradlew test -i

-iはテストが失敗した時に理由を表示するために必要です。

レポートはbuild/test-report/index.htmlにあります。

まとめ

Android StudioでRobolectricは全体的に物足りないという感じです。まだ実際のプロジェクトでは使っていませんが、どっかのタイミングでやりたいと思っています。

参考

補足

gradle-android-test-pluginのREADMEの依存には書いてあるのですが今回は特に触れなかった FEST Android というのがあります。

まだ触ってないのですがEspressoと同じようにテストの記述を簡単にしてくれるっぽいです。時間あったらそのうち調べます。