Help us understand the problem. What is going on with this article?

Robolectricを使ったAndroid端末を使わないユニットテストを行う第一歩

More than 3 years have passed since last update.

本記事では、Robolectricを使ってAndroid端末を使わないユニットテストを行うためにどんなことをすればいいかをまとめた記事です。これを機にRobolectricに興味を持っていただければ幸いです。というよりAndroid端末を使わないでテストやってみよう!って思えればいいかなと思っています。

Robolectricとは?

JVM上でAndroid依存部分のテストを行うためのライブラリです。
JVM上で動かすことができるので
・Android端末を用意せずともActivityやContextが絡むコードのユニットテストを行うことができます。
そして、
・Android端末を使うのよりテストコードの実行時間がはやいです!

公式ホームページは
http://robolectric.org/
です。

執筆時点(2016/2/6)での最新バージョンは3.0です。

今回のテスト対象のアプリ

今回テストに使うアプリは「Permutation計算アプリ」です。二つのパラメータを入力して計算ボタンをタップすると計算結果が表示されるものです。(ちなみにPermutationとは高校数学でいう「順序」のことです。詳しくはこちらを参考にしてください。)

スクリーンショット 2016-02-06 14.09.10.png

ソースコードはGithubにアップロードしています。
https://github.com/LyricalMaestro/RobolectricPractice

クラス構成

app/main/java内のファイル構成をAndroidStudioで表示したものをいかに貼り付けてみました。このアプリはGUI部分を担う「MainActivity」とPermutationの計算を担う「Calculator」(Androidでなくても普通のJVM上で動きます)の二つのクラスから構成されています。

スクリーンショット 2016-02-06 13.43.51.png

テストコードを書いていく

ここから先ほど紹介した「MainActivity」と「Calculator」についてテストを書いていきます。Androidフレームワークを使っていない部分の方が簡単にテストが書けるのでまず「Calculator」からテストを書いていきます。

AndroidでJUnitのコードを書くには?

プロジェクトのデフォルトの設定だとキャプチャ1のように、javaフォルダとして認識されず、テスト実行はおろか自動ビルドも行われないのでテスト効率が下がります。

・キャプチャ1
スクリーンショット 2016-02-06 14.27.34.png

テストコード作成作業効率化のための設定を行います。AndroidStudio左下にある「Build Variants」のタブをクリックします。

スクリーンショット 2016-02-06 14.26.32.png

そしてBuild VariantsパネルのTest Artifactのところを「Unit Tests」に切り替えます。
スクリーンショット 2016-02-06 14.26.55.png

そうするとキャプチャ2のようにtest/javaフォルダがソースコードのフォルダとして認識されます。

・キャプチャ2
スクリーンショット 2016-02-06 14.27.19.png

gradleファイルの設定

Robolectricを使うのでbuild.gradleにRobolectricをインポートするコードを記載します。テストを書くのにJUnitもインポートしないといけないのでは?と思うかもしれませんが、Robolectricをインポートすれば芋づる式にJUnit4もインポートされます。(これはRobolectricを使うのでればJUnit4を使ってテストコードを書くべし、と言われているのと同じことだと思ってください。)

app/build.gradle
dependencies {
   …略…
    testCompile "org.robolectric:robolectric:3.0"
}

モデル部分のテストコードを書く

モデル部分に相当する「Calculator」クラスのテストコードを書いていきます。Calculatorクラス自体はAndroidに一切依存しないクラスなので普通のJUnit4のテストコードを書くノリでかけます。

https://github.com/LyricalMaestro/RobolectricPractice/blob/master/app/src/test/java/com/lyricaloriginal/robolectricpractice/CalculatorTest.java

Androidフレームワークに依存したコードを書いていく

MainActivityのテストコードを書いていきます。ここはバリバリAndroidに依存するコードで構成されているのでRobolectricを使ってテストを書いていきます。

MainActivityTest.java(import情報除外)
/**
 * MainActivityのテストコード
 *
 * Created by LyricalMaestro on 2016/02/06.
 */
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.LOLLIPOP)
public class MainActivityTest {

    @Test
    public void calculateBtn() {
        MainActivity mainActivity = Robolectric.setupActivity(MainActivity.class);
        setValueToEditText(mainActivity, R.id.input_n, "5");
        setValueToEditText(mainActivity, R.id.input_m, "3");

        mainActivity.findViewById(R.id.calculate_btn).performClick();

        TextView resultView = (TextView)mainActivity.findViewById(R.id.result_view);
        assertThat(resultView.getText().toString(), is("5P3 = 60"));
    }

    private void setValueToEditText(MainActivity mainActivity, int viewId, String value) {
        EditText editText = (EditText)mainActivity.findViewById(viewId);
        editText.setText(value);
    }
}

class側にアノテーションをつけているのと、Activity生成時にRobolectricのクラスを使っているところ以外は普通にJUnit4のノリで書けます。メソッドの中身は公式ホームページのサンプルコードみながら簡単なものはサクッとできますが、アノテーション周りについては知らないとはまってしまう可能性があるので以下、そこだけ特記します。(完全な私の体験談だったりしますが)

1. @RunnerにはRobolectricGradleTestRunner.classを指定すること

公式ホームページのチュートリアルではRobolectricTestRunner.classが使われていますが、これだとresフォルダ、assetsフォルダ、ひいてはAndroidManifest.xmlすらも使われなくて、レイアウト関連のテストがこのままだとできなくなります。これに対する方法は「カスタムTestRunner」を実装しなければいけません。
RobolectricGradleTestRunnerは上記の問題に対する対応をしっかり行ったカスタムTestRunnerです。

2. @Configにはsdkを指定しておくとはまらずに済む

sdkオプションをつけない場合、app/build.gradleのtargetSdkVersionの番号で動きます。Robolectricは現段階でバージョン16,19,21でのみ対応していますが、targetSdkVersion=23とかやってしまうとRobolectric側が「対応していません!」というエラーがでてテストが実行できません。
なのでsdkオプションをつけて明示的にどのバージョンで動かすかを指定してあげる必要があります。

ユニットテストを実行する

ユニットテストを実行する方法は以下の二通りです。

1. コマンドラインから実行

ターミナル上で./gradlew testを実行すればOKです。(もちろんプロジェクトフォルダまで移動してから行うことですが)
テスト結果のレポートはapp/build/reports/testsフォルダ内に保存されます。
(ターミナル上でopen app/build/reports/tests/[debug or release]/index.htmlを実行するとテスト結果のレポートがブラウザ上で確認することができます。)

2. AndroidStudio上から実行

慣れないとちょっと大変ですが慣れればやりやすいと思います。

まず、Build VariantsパネルのTest Artifactを「Unit Test」にしておいてください。その上で話をすすめていきます。

JUnitのデフォルト設定の変更

これは最初の一回だけで大丈夫です。

  1. AndroidStudio上部のツールバーから「Edit Configurations…」を選択。 スクリーンショット 2016-02-06 23.42.36.png
  2. [Defaults]-[Junit]タブを選択。その後、Working directoryの部分を「$MODULE_DIRS」に書き換えて、Apply. スクリーンショット 2016-02-06 23.44.39.png

JUnit実行設定の作成

  1. テストを行いたい対象を選択し、右クリック。メニューの「Select 'XXXXXX'」をクリック。(すると、テスト実行設定に追加されます。)
  2. そのまま、Run 'XXXXXXX'を実行すればユニットテストが実行されます。

結果についてはapp/build/reports/testsフォルダ内に保存されます。

Android端末を使ったテスト(AndroidJUnit4)は完全に「いらない子」か?

Robolectricは素晴らしいフレームワークですが、これでユニットテストの全てを賄えるわけではありません。特別な端末について実際テストするとき、もしくはAndroid6.0代でテストしたいときなどはAndroidJUnit4を使います。
この両方を使い分けるためにtestフォルダ, androidTestフォルダ両方にテストコードを書かないといけません(Androidフレームワークに依存するところだけは)。これはメンテナンスする上ではかなり厄介な構造になります。

それを解決するための方法が以下のページで紹介されていますが、実際試していないのでどこまですごいかはわかりません。ただ使えるなら使ってみてはいかがでしょう。

http://gfx.hatenablog.com/entry/2015/12/30/011313

まとめ

Robolectricをうまく使うことによってAndroid端末なしでユニットテストを行うことができます。その環境を構築する手順、実際のやり方について今回具体的なプログラムを介して説明しました。

私自身、このRobolectricを使って数日しか経っていないのでRobolectricで他にどんなことができるかがきちんとは把握しきれていません。今後使っていきながら何ができるかを把握し、Android端末なしユニットテストの環境をバシバシ整備していきたいと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away