2016/06/25

[android]AARのテストをしてみよう!

ぼちぼち、Androidのテストをせねばならぬ。
TwoSpinnersでいろいろやっていたのは、あれは結合テスト的な、実際に動かすテストだったのだけど、ユニットテストのやり方も知っておきたい。

Android Studio 2.1.2でやってみよう。


Android Studioでプロジェクトを新規作成し、Activityだけを持つアプリを作った。
そしてそこに、New ModuelesでAndroid Libraryを追加。
com.hiro99ma.blogpost.myaarというのがそれだ。

デフォルトでExampleUnitTestというものがあるので、それを動かしてみよう。
ツリーから右クリックし、'Run ExampleUnitTest'を選択。

image

エラーだ。

Process finished with exit code 1
Class not found: "com.hiro99ma.blogpost.myaar.ExampleUnitTest"Empty test suite.

あるのに!
AARだからダメなのかと思ったが、appの方も同じだった。
何かしないとダメらしい。


Building Local Unit Tests | Android Developers

今回やろうとしているのは、Local Unit Testということになる。
書いてあることは、

  • build.gradleのdependenciesにjunit(とオプションでmockito)を追加
  • テストclassを作る
  • Mockのことを飛ばすと、もうRun Local Unit Tests

手順が違うように見えないが。。。

あ、「Sync Projectしろ」とあるな。
ツールバーのアイコンをクリックして、同じようにRunさせると、今度は動いた!

image

Syncしてなかっただけ、ということか。
でも、Syncが必要なときはだいたいメッセージが出ていたと思うが。。。
まあいい。


ちなみに、テスト内容は「assertEquals(4, 2 + 2);」と単純なものだ。
最初に期待値を書いて、次に評価対象を書く。
逆でも結果としては変わらないと思うけど、たとえば第1引数を5にして失敗させると、こうなる。

image

ExpectedとActualが出力されるので、やっぱり期待値と評価対象は合わせておいた方がよいだろう。
私はGoogleTestでそれを知らず、全部引数を逆に書いてがっかりしたことがあるのでね。。。


では、自分でclassを作って、それのテストまでやってみよう。

public class MyAar {
    private Context mContext;

    public MyAar(Context context) {
        mContext = context;
    }

    public String getString(int resId) {
        return mContext.getString(resId);
    }
}

エディタ側の方で、クラス名にカーソルを当てていると電球マークが出てくるので、マウスでクリックしてメニューを開く。
Alt+Enterでもよいかも。
「Create Test」があるので、選択。

image

Android 2.1.2では、こういう画面が出てきた。

image

setUp, tearDown、あとはgetString()にチェックしてOK。
そうすると、Choose Destination Directoryダイアログが出てくる。

image

2つ候補が出てくるが、開いたときは下の方がフォーカスされていた。
上の方はApplicationTest.javaが既にあって、これはテストのメイン処理みたいなものじゃなかろうか。
だから、デフォルトのままでよかろう。
そうすると、MyAarTestというクラスを作ってくれた。

public class MyAarTest {

    @Before
    public void setUp() throws Exception {

    }

    @After
    public void tearDown() throws Exception {

    }

    @Test
    public void testGetString() throws Exception {

    }
}

まあ、空っぽですな。

じゃあテストを書いてみようか、というところで、Contextをどうやって持ってきてよいかということになる。

ここでまた、Android Developerのサイトに戻ろう。


Mock Android dependencies

Mockitoというのを使うと、いいらしい。
伊藤さんのMockか、と思ったが、モヒートらしい。。。

サイトではbuild.gradleのdependenciesに追加しているが、こういうのはGUIからでもできたはず、とProject StructureのDependenciesで「mockito-core」を検索してみた。

image

betaねぇ。。。
まあいいや、それにしてみよう。
build.gradleも見ておく。

testCompile 'junit:junit:4.12'
androidTestCompile 'org.mockito:mockito-core:2.0.71-beta'

追加されたのだけど、最初からあるjunitとちょっと違うな。
まあ、それもよしとしよう。

サイトをまねして@Mockと書いたが、classの前に「@RunWit(MockitoJUnitRunner.class)」の記載もいるようだ。
が、それを追加してもまだだめで、MockitoJUnitRunner.classすらも怒られている。
importを追加しても、そんなの使ってないよ、という感じだ。

ここで、build.gradleのandroidTestCompileをtestCompileに変更すると、直った。
ちっ。


そんなこんなで書いたのが、こういうテストclass。

@RunWith(MockitoJUnitRunner.class)
public class MyAarTest {
    MyAar mAar;

    @Mock
    Context mMockContext;

    @Before
    public void setUp() throws Exception {
        mAar = new MyAar(mMockContext);
    }

    @After
    public void tearDown() throws Exception {
        mAar = null;
    }

    @Test
    public void testGetString() throws Exception {
        Mockito.when(mMockContext.getString(R.string.app_name)).thenReturn("Hello");
        String str = mAar.getString(R.string.app_name);
        assertThat("Hellos", is(str));  //★第1引数がExpectedのつもりで書いてる
    }
}

最後のassertThat()は、サイトのをまねした。
失敗させないと、動いているかどうかわからんので、Mockの方は"Hello"、期待値は"Hellos"としてみた。

結果は、

image

ああ、ちゃんと失敗しているね。

ん?
Expectedが"Hello"になってる。。。
引数の意味がassertEqual()とは逆なのか。

Assert (JUnit API)
第1引数がactualで、第2引数がMatcherというものらしい。

なんというか、言葉をしゃべるように、

assertThat(実際の値, is(期待値))
  →「実際の値 is 期待値」

ということかしらね。
まあ、私も期待値を後ろに書きたい方だからよいのだけど、他のassertと順番が逆なのは嫌だな。

こちらに、assertThat()じゃないと回避できないというか不便というか、そういう問題があるという話が載っていた。
assertEquals()は古い。assertThat()+Matcherを使う。 : Java好き

特にこだわりが無いなら、assertThat()にしておけば困らないのかな。
ただ、見た目が「assertTrue()」に似てるので、そこは気をつけねば。。。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。