リア充爆発日記

You don't even know what ria-ju really is.

外部ライブラリプロジェクトを使ったプロジェクトをIntelliJとMavenで両立させる

りーむー。それはりーむー。

2日使った結論。

ここでいう”両立"というのは、どっちからでもビルドアンドデプロイができる状態を成立させて維持するという意味で。

"apklib dependencyコマンドラインからじゃないと機能しない"
http://stackoverflow.com/questions/8831481/apklib-does-not-get-installed-in-maven-repo/8831891#8831891

そうなると、結局IDE用にはhttp://d.hatena.ne.jp/ria10/20121030/1351618290の方法でライブラリプロジェクトとして関連付ける必要がある。
が、そうすると、今度はmaven側の設定と競合して超絶ややこしい。

mavenプロジェクトにするとpomの記述にあわせてIDE側の設定も変えられてしまうのでこの2つを共存させるのはくやしいが今の俺のポム力では無理だ!
CI導入時を見越してついでにここらでがんばっておくか、と思ってやったけどちょっとシャレにならないくらい時間を使ってしまった。

これはこれでいい経験になったと思って、CIのときはCI用にポムることにする。
Jarの依存関係だけならMavenIntelliJの組み合わせでうまくいっているし、これだけでも相当メリットあるし。

あとスタックオーバーフロー最強。英語読めないWEBエンジニアはオワコン化していく確率高いと思うね。

しかしぐやじいのぅ。もっと早く判断できていれば・・・。

Androidのテストツールならこれ!Robolectric導入の儀。

かつてはAndroid依存のモジュールのテストはド遅いからPOJOとうまく分離してなるべくPOJOを通常のUnitテストで・・・とか思っていた時期があったんだけど、この分離ってやつが相当キツくて。ンカスプログラマだから。

つまりテスト書いてなかったんだけど、それはまだAndroid開発のノリがわかってなかったこともあったし、開発対象が画面の遷移周りがメインであまり小難しい処理がなかったんで、テストによるメリットよりデメリットが上回る可能性があったからで。

今はかなりわかってきたし、細かい実装もやっていかにゃあ、なんでもう一度テストについてよく調べてみたのよ。

そもそもAndroidモジュールが絡むテストが遅いのは

  • Googleandroid.jarにある全メソッドを"throw new RuntimeException("Stub!");"に変えている
  • そのため、エミュレータなり実機なりで動かさないといけない(モックに差し替える前に例外が飛ぶのでMockingもりーむー)
  • ということはDex(確かDalvikVMでうごくバイトコードにする処理)やらインストールやらが必要なのでド遅い。

ということなんだけど、なんと!黒魔術にてこの"throw new RuntimeException("Stub!");"を差し替えてよしなにやってくれるフレームワークがありました!

Robolectric
この会社の人たちはIntelliJを使ってます!イェー!


で、IntelliJに途中から導入する手順も公式に書いてあるんだけど、なんかよくわからない手順だったので無視して勝手にやってうまくいった方法を以下に。

前提

  • IntelliJは123.4(EAP)を使用 ※けっこう問題なくイケるよ!
  • すでにMavenizeされたプロジェクトがある※過去記事参照
  • OSX10.8

pomにちょろっと足す

        <!-- TEST DEPENDENCIES -->
        <!-- Robolectric -->
        <dependency>
            <groupId>com.pivotallabs</groupId>
            <artifactId>robolectric</artifactId>
            <version>1.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>

これ、なるべく上にもっていってほいたほうがいいです。理由は後述。

依存関係の設定をする

Project Setting > Modules > アプリ > Dependenciesタブ
で、テスト関係のモジュールをAndroidSDK(黄色い玉のやつ)より上に持っていく。これをしないと"java.lang.RuntimeException: Stub!"がでる。で、さっきpomでテストモジュールの記述をなるべく上に、という話をしたのは、この上に持っていく作業がちょっとだけ楽だから。だからやっぱりpom上では上に持っていかなくてもいいです。


Sourceの設定をする

Project Setting > Modules > アプリ > Sourcesタブ
で、Source Foldersがsrc/main/java、Test Source Foldersがsrc/test/javaになっているようにする。Mavenのスタンダードストラクチャーってやつね。他のがあったらもしかしたら邪魔になるかもしれないから、要らないと思ったら消しておく。


テストを作る

とりあえず適当に。

import com.xtremelabs.robolectric.RobolectricTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;

/**
 * User: ria10
 * Date: 2012/11/27
 * Time: 16:35
 */
@RunWith(RobolectricTestRunner.class)
public class MyActivityTest {
    @Test
    public void shouldNotBeNull() throws Exception {
        MyActivity activity = new MyActivity();
        assertThat(activity, is(notNullValue()));
    }

}

ということで、@RunWith(RobolectricTestRunner.class)を書くことがRobolectricを使う、ということになります。この超簡単なテストではそれ以外にRobolectric依存の記述はありません。

実行

超フツーに実行するだけ。

ただ、

java.lang.RuntimeException: java.lang.ClassCastException: com.xtremelabs.robolectric.RobolectricTestRunner cannot be cast to com.xtremelabs.robolectric.internal.RobolectricTestRunnerInterface

が出たら、たぶんそれはお使いのJUnitのバージョンがRobolectricにあってないから。4.11はダメ。4.10なら大丈夫。
https://groups.google.com/forum/#!msg/robolectric/dtvMJSr5HkQ/VA3F3ZcCmekJ

pom書き換えると、DependenciesのところでまたTestモジュールたちがAndroidSDKより下にきちゃうから再設定が必要なのが微妙だけど仕方ない。



イェー!!ハッピーテスティング