SlideShare a Scribd company logo
GroovyなAndroidテスト
             8.9.2012
  Takahiro Yoshimura (@alterakey)
こんな人


埼玉で活動しているアーキテクト

Webサービスやスマートフォンアプリなどを作っています

Androidは…まだそこそこ (汗)
テスト、間に合ってます?

標準添付のAndroid Testing Framework…

実機で動かすタイプ

しかし実機で動かしていると遅い!
→ABS、Guavaなどを入れると簡単に数分台のビルド時間
→ProGuardなどでShrinkすれば良いが…

高速化は本質的に困難
そこでGroovyですよ!
背景
Groovyって何?

 JVMで動作する動的言語の一種

 Javaと違って型や制約にうるさくない
 →privateメソッドだろうが何だろうが呼べる
 →Assertionが親切!
 →テストに最適

 Javaで書かれたライブラリなども利用可能
Androidでは?


残念ながら、Android開発には簡単に使用できない
Discobotなどの成果もあることにはあるが…

しかしJVMで動作させても良いテストには有効
…は?JVM?

JVMでAndroidなんか動かないだろうが…

android.jarを追加してもシステムクラスにはほぼ触れない

java.lang.RuntimeException: Stub!

Androidシステムクラスをテストしたいが…

                                    … orz
Robolectric!

AndroidアプリをJVMでテストするためのフレームワーク

Androidシステムクラスをことごとく置き換えてテスト可能に

 ActivityやServiceといったものをそのままnew…!

 SQLite系ですらエミュレート

 Fragmentは…
 Support Packageを使っていればOK
だが面倒だ

GroovyやRobolectricを落としてきて、別途インストールしたり

EclipseではJUnitプロジェクトを立てていろいろ設定を…(ry

Antではcustom_rules.xmlを作成していろいろルールを…(ry

                                    … orz
もったいない…
ということでAndroid Ant Runnerを作りました
→ http://github.com/taky/android-runner (BSD)

GroovyやSpockを始めとするテストツールキットを
Antベースのプロジェクトから簡単に使えるようにするパッケージ
(Android SDK r20以上)

Eclipseは?IDEAは?Mavenは?Gradleは? …すみませんが (ry

Unix系限定です… ごめんなさい m(_ _)m
そもそも



なんでテストテスト言っているの?
テストは設計手段の一つ

詳細仕様を先に定義、コードはそれに合わせる形に

クラスの「詳細設計書」としてのユニットテスト

振舞駆動開発(BDD)


→ プロジェクトに参加しやすく、リファクタリングもしやすく
軽くデモ
コマンドライン+テキストエディタ

導入∼結合テストまで

テキストビューア
Intentを受け取ってContentResolverに渡してTextViewに表示

YouTubeにあります…
http://www.youtube.com/watch?v=nrT50tpIjZE
では詳細に



導入
GroovyなAndroidテスト #atest_hack
導入

Githubからcloneしてきてbootstrapするだけ!

 詳細はREADMEに記載

これでGroovy、Spock、Robolectricその他諸々全て手に入る!

すぐにでもユニットテストを書ける状態に!
Activityの設計

MainActivity: メイン画面

「This is a text viewer.」と書いてあること

まずはテストケースから
Activityについては結合テストにも一応書いておく
※実機で問題があれば把握したいため

ここからがほぼGroovy!
Activityの設計

integration/.../MainActivityTest.java:

public class MainActivityTest extends ActivityInstrumentationTestCase2<...> {
  ...
  public void test_000() {
      getActivity();
  }
}
Activityの設計
unit/.../MainActivityTest.groovy:
import spock.lang.*
@RunWith(TestRunner)
class MainActivityTest extends Specification {
   @Test def test_000() {
      def o = new MainActivity()
      o.onCreate(null)
      when:
      def tv = o.findViewById(R.id.view)
      then:
      tv.getText() == This is a text viewer.
  }
}
Activityの設計
Spockで仕様が読みやすくなる!

I. Groovyのみ                        II. Groovy+Spock
// 初期状態                            setup:           // (省略可)
def o = new MainActivity()         def o = new MainActivity()
o.onCreate(null)                   o.onCreate(null)
// こうした場合                          when:
def tv = o.findViewById(...)        def tv = o.findViewById(...)
// こうあるべき                          then:
assertEquals(tv.getText(), ... )   tv.getText() == ...
Activityの設計

RobolectricはJUnit 4.x、Android JUnitはJUnit 3.x
→4.xは @Test Annotationで、3.xは名前でテストを特定

@RunWith(TestRunner)
→Robolectric標準を多少カスタムしたテストランナー
→AARでRobolectricを使うにはこのAnnotationが必要

テストランナーは複数指定できない
→テストフレームワーク間で取り合いになりやすい orz
Activityの設計
Robolectricはパラメタライズドテストを扱えない

つまり
「Spockのexpectを使って似通ったテストをまとめて簡潔に!」

                                 → 今はまだムリ orz

単純にRobolectricTestRunnerの問題なので、Robolectricを
ルールなどの形で再実装できれば解決するかも

もちろんRobolectricを使わないテストならパラメタライズ可能
GroovyなAndroidテスト #atest_hack
しくじったよ!

実装していないので当然

ここから実装を書いて成功させる

 res/layout/main.xmlのTextViewに:

   IDを振ってメッセージを入れる
GroovyなAndroidテスト #atest_hack
成功だ!次は?



ViewActivity: 表示画面

Intent.ACTION_VIEWを受けとって中身を表示できること
Activityの設計



まず表示できること
Activityの設計

integration/.../ViewActivityTest.java:

public class ViewActivityTest extends ActivityInstrumentationTestCase2<...> {
  ...
  public void test_000() {
      getActivity();
  }
}
で、実際の挙動は…??

Intent.ACTION_VIEWを受けとって中身を表示できること

しかし、どうやってロードしたことを確かめる?

Intentはどこからどう飛ばす?

テストデータはどう準備すれば?
テスト可能性を考えて…

ここではTextLoaderとしてロード処理を分離
→テスト時はハリボテ(スタブクラス)を噛ませる

Activityは単にUIに専念させる
→いろいろやっているクラスはテストが難しくなりがち
→テストしやすくするためには設計の工夫が必要!

IntentはRobolectricで飛ばしたことにできる!
→Robolectricのテスト用クラスに直接渡す
Activityの設計
unit/.../ViewActivityTest.groovy:

@RunWith(TestRunner)
class ViewActivityTest extends Specification {
   @Test def test_000() {
      # TBD: LOAD HERE, with TextLoader!
      def o = new ViewActivity()
      o.onCreate(null)
      when:
      def tv = o.findViewById(R.id.view)
      then:
      tv.getText() == File read!
   }
}
Activityの設計

unit/.../ViewActivityTest.groovy:

@Test def test_000() {
  ...
  def o = new ViewActivity()
  def intent = new Intent(Intent.ACTION_VIEW)
  intent.setData(Uri.parse( content://test-1 ))
  Robolectric.shadowOf(o).setIntent(intent)
  o.onCreate(null)
  ...
スタブはどう作れば…


Groovyならスタブの作成も楽々…なはずなのだけど

Javaから呼び出されるクラスはGroovyではモックできない!

Mockitoを使えばOK
→Android Ant Runnerに同梱してある
で、スタブはどう作れば…

def o = mock(XXX)とした後に…

when(o.method1()).thenReturn( foo )
when(o.method2(anyObject()).thenReturn( bar )
when(o.method2(eq(null))).thenThrow(new NullPointerException())
→ o.method1()     foo
  o.method2(Object arg)         bar
  o.method2(null)     NullPointerException(例外)
で、スタブはどう作れば…


簡単なものなら一行で書きたい! …書けますよ?

def o = mock(XXX)
when(o.method()).thenReturn( foo )

def o = when(mock(XXX).method()).thenReturn( foo ).getMock()
Activityの設計
unit/.../ViewActivityTest.groovy

@Test def test_000() {
  ...
  # TBD: LOAD HERE, with TextLoader!
  def loader = when(mock(TextLoader).read()).thenReturn( File read! ).getMock()
  def loader2 = when(mock(TextLoader).read()).thenReturn( ).getMock()
  def builder = mock(TextLoader.Builder)
  when(builder.build(anyObject(), anyObject())).thenReturn(loader)
  when(builder.build(anyObject(), eq(null))).thenReturn(loader2)
  def o = new ViewActivity()
  ...
で、スタブはどう渡せば…

unit/.../ViewActivityTest.groovy

def test_000() {
  ...
  def o = new ViewActivity(builder)
  ...


                                      …!!
で、スタブはどう渡せば…


Dependency Injection (DI)
→パラメータなどとしてコラボレータを外部から導入する手法
→クラス間の結合度を低下させることができる

今回はコンストラクタ(ctor)へ導入
→空のctorも作っておく必要があることに注意
で、スタブはどう渡せば…

Guiceなどを使うとより手軽に適用可能…なはずなのだが
そもそもAndroidではInversion of Controlされている環境
(i.e. Activityなどはシステムが勝手に作るもの)
→これが空のctorを要求される理由

いつinjectorを初期化するのかが問題に
→RoboGuiceでは専用クラスを継承させている(!!)
で、スタブはどう渡せば…



Guiceはともかく、RoboGuiceは
自動テストの役にはあまり立たなそうな…?
GroovyなAndroidテスト #atest_hack
実装



テスト失敗、実装へ…

TextLoaderは骨組だけ
GroovyなAndroidテスト #atest_hack
注意


ViewActivityの画面構成についてはテストしていない

結合テストで「最低限表示できる」レベルを担保
→まだ動かしていないけど…
次は?


TextLoader: テキストローダ
.read() → あらかじめ指定されたURIの内容をStringで

これもテストケースから(ry
ロジックの設計

unit/.../TextLoaderTest.groovy:

@RunWith(TestRunner)
class TextLoaderTest extends Specification {
   @Test def test_000() {
       when:
       def o = new TextLoader(new Activity(), Uri.parse( content://test-1 ))
       then:
       o.read() == Test file 1
   }
   ...
ロジックの設計

unit/.../TextLoaderTest.groovy:

  ...
  @Test def test_001() {
      when:
      def o = new TextLoader(new Activity(), null)
      then:
      o.read() ==
  }
  ...
GroovyなAndroidテスト #atest_hack
テスト失敗、実装を…
書いたはいいよ?



でもContentResolverなんてどうやってテストする?
Robolectric!


独自クラスで置換することもできる
→継承している必要すらない

もちろんContentResolverも例外では…ないッ!
ということで

ShadowContentResolverクラスを作成、
ContentResolverとして振る舞わせることに。

SCR.openInputStream(Uri):

   content://test-1 → Test file 1 と読めるInputStream

  その他 → null

TestRunner.bindShadowClassesに追記。
ContentResolverの影

unit/.../TestRunner.java:

public class TestRunner extends RobolectricTestRunner {
  ...
  protected void bindShadowClasses() {
      super.bindShadowClasses();
      Robolectric.bindShadowClass(ShadowSimpleAdapter.class);
      Robolectric.bindShadowClass(ShadowContentResolver.class);
  }
}
ContentResolverの影


unit/.../ShadowContentResolver.java

長いので割愛します m(_ _)m
YouTubeのデモを参照して下さい…
http://www.youtube.com/watch?v=nrT50tpIjZE
GroovyなAndroidテスト #atest_hack
成功!次は!



いよいよ実機で
GroovyなAndroidテスト #atest_hack
orz
ぐぬぬぬぬ…

MainActivityはいい…
しかしViewActivityがピヨピヨしていることが判明

なぜ?→AndroidManifest.xmlに宣言されていないらしい

Error in test_000:
java.lang.RuntimeException: unable to resolve activity for Intent { action=...
  flg=... cmp=... /.ViewActivity }
  at ...
  at ...
ぐぬぬぬぬ… (2)



AndroidManifest.xmlにViewActivityの宣言を追加

ついでにSDKバージョンの宣言も
GroovyなAndroidテスト #atest_hack
成功!



すっきり!
GroovyなAndroidテスト #atest_hack
まとめ

Android JUnitは実機でテストできるが、ビルドが非常に遅い

GroovyはJVMで動作する簡潔・動的な言語
→静的な型に縛られない書き方ができるのでテスト向き
→実装の関係上、Android開発で使用するのはまだ難しい…

実機で動かさないテストならGroovyで十分にできる
→TDD/BDDが現実的に!
まとめ


JVM上でAndroidシステムクラスは本来テストできないが、
Robolectricを使うとテスト可能になる

Activityのテストを行なう場合にはユニットテストだけでなく、
Android JUnitによる結合テストも併用すると良い
まとめ


Spockを併用するとテスト仕様をより読みやすく記述できる

Robolectric自体はまだパラメタライズドテストを扱えない
→expect+whereのような華麗なテストはできない…
→ランナーの問題なのでルールなどの形にできれば解決するかも
→もちろんRobolectricを絡ませなければパラメタライズ可能!
まとめ

Javaから呼ばれるクラスはGroovyでモックできないので、
Mockitoなどのモックフレームワークを併用する必要がある

Robolectricを使うと任意のクラスをAndroidシステムクラスとし
て振る舞わせることができる

AndroidのクラスをモックするにはRobolectric
自前のクラスをモックするにはモックフレームワーク
まとめ



Android Ant Runnerを使うとテスト環境を簡単に整備できる

http://github.com/taky/android-runner (BSD)
ご静聴ありがとうございました。




Credits: Music by "FIGHTER X” – "Time to die" in album “REBOOT2,” © 2012 chipcon.org, used under the Creative Commons 3.0 Attribution-NonCommercial-NoDerivs Unported license: http://creativecommons.org/licenses/by-nc-nd/3.0/

More Related Content

What's hot (20)

PDF
Java SE 9の紹介: モジュール・システムを中心に
Taku Miyakawa
 
PDF
BNN CAMP vol.3  インタラクションデザインの現在―プログラミング初心者のためのopenFrameworks入門 1
Atsushi Tadokoro
 
PPTX
JJUG CCC 2017 Fall オレオレJVM言語を作ってみる
Koichi Sakata
 
PDF
xUnit Test Patterns - Chapter11
Takuto Wada
 
PPTX
Deep Dive C# 6.0
信之 岩永
 
PPTX
Orange Cube 自社フレームワーク 2015/3
信之 岩永
 
PDF
C# から java へのプログラム移植で体験したtddの効果は?
Shinichi Hirauchi
 
PDF
Groovy Bootcamp 2015 by JGGUG
Uehara Junji
 
PDF
Unowned / Weak References with Closure
Naruki Chigira
 
PDF
Xtend30分クッキング やきに駆動
Shinichi Kozake
 
PDF
Groovy Shell Scripting 2015
Uehara Junji
 
PDF
デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 1: openFrameworks入門
Atsushi Tadokoro
 
PDF
Unit test in android
Tatsuya Maki
 
PDF
GroovyServ concept, how to use and outline.
Uehara Junji
 
PDF
Swift 2.0 で変わったところ「後編」 #cswift
Tomohiro Kumagai
 
PDF
Eclipse ADTとAndroidStudio両方で動かせる開発環境構築
kimukou_26 Kimukou
 
PDF
OpenCV4Androidで画像処理アプリのススメ
Masaki Otsuki
 
PDF
覚醒!JavaScript
Haraguchi Go
 
PPTX
OpenCVを用いた画像処理入門
uranishi
 
PDF
オープンソースで作るスマホ文字認識アプリ
陽平 山口
 
Java SE 9の紹介: モジュール・システムを中心に
Taku Miyakawa
 
BNN CAMP vol.3  インタラクションデザインの現在―プログラミング初心者のためのopenFrameworks入門 1
Atsushi Tadokoro
 
JJUG CCC 2017 Fall オレオレJVM言語を作ってみる
Koichi Sakata
 
xUnit Test Patterns - Chapter11
Takuto Wada
 
Deep Dive C# 6.0
信之 岩永
 
Orange Cube 自社フレームワーク 2015/3
信之 岩永
 
C# から java へのプログラム移植で体験したtddの効果は?
Shinichi Hirauchi
 
Groovy Bootcamp 2015 by JGGUG
Uehara Junji
 
Unowned / Weak References with Closure
Naruki Chigira
 
Xtend30分クッキング やきに駆動
Shinichi Kozake
 
Groovy Shell Scripting 2015
Uehara Junji
 
デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 1: openFrameworks入門
Atsushi Tadokoro
 
Unit test in android
Tatsuya Maki
 
GroovyServ concept, how to use and outline.
Uehara Junji
 
Swift 2.0 で変わったところ「後編」 #cswift
Tomohiro Kumagai
 
Eclipse ADTとAndroidStudio両方で動かせる開発環境構築
kimukou_26 Kimukou
 
OpenCV4Androidで画像処理アプリのススメ
Masaki Otsuki
 
覚醒!JavaScript
Haraguchi Go
 
OpenCVを用いた画像処理入門
uranishi
 
オープンソースで作るスマホ文字認識アプリ
陽平 山口
 

Similar to GroovyなAndroidテスト #atest_hack (20)

PDF
Android test tutorial
Kazuaki Ueda
 
PDF
はてなにおける Android アプリのソフトウェアテスト
Yu Nobuoka
 
PDF
ABC 2011 Summer
miyatay
 
PDF
ABC
Yumi Miyata
 
KEY
テスト初心者Androiderのためのソフトウェアテスト入門
Satoshi Watanabe
 
PDF
GUI Test is (not) necessary
Hiroshi Maekawa
 
PPTX
JaSST'16 Tokyo モバイルセッション
mirer
 
PDF
今更聞けない? Androidのテストのいろは
Hiroshi Kikuchi
 
PPTX
Robotium を使った UI テスト
Kenichi Tatsuhama
 
PDF
Androidテスティング実践2 システムテスト編
株式会社 NTTテクノクロス
 
PPTX
Sansan における Android アプリ自動テスト導入事例
Kenichi Tatsuhama
 
PDF
Androidテスティング実践 基礎編
株式会社 NTTテクノクロス
 
KEY
Androidリリース作業の効率化(2)
Kenichi Kambara
 
PDF
Androidテスティング実践3 ユニットテスト・CI編
株式会社 NTTテクノクロス
 
PDF
受託開発でテストファーストしたらXXXを早期発見できてハイアジリティになったはなし
terahide
 
PDF
わんくま名古屋 #40 (20161217) Xamarinで自動化テストしよう
Yasuhiko Yamamoto
 
PPTX
Junit4
ichikaz3
 
PDF
ABC2011w_テスト部
miyatay
 
PPTX
Android 開発, 運用時に使いたいライブラリやサービスの紹介
Kenichi Tatsuhama
 
PDF
Nds#24 単体テスト
Kazumune Katagiri
 
Android test tutorial
Kazuaki Ueda
 
はてなにおける Android アプリのソフトウェアテスト
Yu Nobuoka
 
ABC 2011 Summer
miyatay
 
テスト初心者Androiderのためのソフトウェアテスト入門
Satoshi Watanabe
 
GUI Test is (not) necessary
Hiroshi Maekawa
 
JaSST'16 Tokyo モバイルセッション
mirer
 
今更聞けない? Androidのテストのいろは
Hiroshi Kikuchi
 
Robotium を使った UI テスト
Kenichi Tatsuhama
 
Androidテスティング実践2 システムテスト編
株式会社 NTTテクノクロス
 
Sansan における Android アプリ自動テスト導入事例
Kenichi Tatsuhama
 
Androidテスティング実践 基礎編
株式会社 NTTテクノクロス
 
Androidリリース作業の効率化(2)
Kenichi Kambara
 
Androidテスティング実践3 ユニットテスト・CI編
株式会社 NTTテクノクロス
 
受託開発でテストファーストしたらXXXを早期発見できてハイアジリティになったはなし
terahide
 
わんくま名古屋 #40 (20161217) Xamarinで自動化テストしよう
Yasuhiko Yamamoto
 
Junit4
ichikaz3
 
ABC2011w_テスト部
miyatay
 
Android 開発, 運用時に使いたいライブラリやサービスの紹介
Kenichi Tatsuhama
 
Nds#24 単体テスト
Kazumune Katagiri
 

More from Takahiro Yoshimura (20)

PDF
Looking Back 2023
Takahiro Yoshimura
 
PDF
Fill In The Blank
Takahiro Yoshimura
 
PDF
Ticket To The Dark World
Takahiro Yoshimura
 
PDF
Looking back 2022
Takahiro Yoshimura
 
PDF
Hazy Datagrams
Takahiro Yoshimura
 
PDF
Wartime Pigeons
Takahiro Yoshimura
 
PDF
Securing Supply Chains
Takahiro Yoshimura
 
PDF
Looking Back: CIS on Managed K8S
Takahiro Yoshimura
 
PDF
Beijing Report 2022
Takahiro Yoshimura
 
PDF
Asynchronicity
Takahiro Yoshimura
 
PDF
Outsmarting Smartphone Apps 2
Takahiro Yoshimura
 
PDF
Outsmarting Smartphone Apps 2
Takahiro Yoshimura
 
PDF
Outsmarting Smartphone Apps
Takahiro Yoshimura
 
PDF
Drawing Dataflow On Dalvik Bytecodes
Takahiro Yoshimura
 
PDF
Trueseeing: Effective Dataflow Analysis over Dalvik Opcodes
Takahiro Yoshimura
 
PDF
10 (about make 10 with 4 numbers challenge)
Takahiro Yoshimura
 
PDF
Go goes Mobile: Quick Exploration on Go 1.5 and Gomobile
Takahiro Yoshimura
 
PDF
Android Wear: Good Parts
Takahiro Yoshimura
 
PDF
DEFCON21×S2 REPORT
Takahiro Yoshimura
 
KEY
伝授の巻について #スクエアフリーセミナー #yochiand
Takahiro Yoshimura
 
Looking Back 2023
Takahiro Yoshimura
 
Fill In The Blank
Takahiro Yoshimura
 
Ticket To The Dark World
Takahiro Yoshimura
 
Looking back 2022
Takahiro Yoshimura
 
Hazy Datagrams
Takahiro Yoshimura
 
Wartime Pigeons
Takahiro Yoshimura
 
Securing Supply Chains
Takahiro Yoshimura
 
Looking Back: CIS on Managed K8S
Takahiro Yoshimura
 
Beijing Report 2022
Takahiro Yoshimura
 
Asynchronicity
Takahiro Yoshimura
 
Outsmarting Smartphone Apps 2
Takahiro Yoshimura
 
Outsmarting Smartphone Apps 2
Takahiro Yoshimura
 
Outsmarting Smartphone Apps
Takahiro Yoshimura
 
Drawing Dataflow On Dalvik Bytecodes
Takahiro Yoshimura
 
Trueseeing: Effective Dataflow Analysis over Dalvik Opcodes
Takahiro Yoshimura
 
10 (about make 10 with 4 numbers challenge)
Takahiro Yoshimura
 
Go goes Mobile: Quick Exploration on Go 1.5 and Gomobile
Takahiro Yoshimura
 
Android Wear: Good Parts
Takahiro Yoshimura
 
DEFCON21×S2 REPORT
Takahiro Yoshimura
 
伝授の巻について #スクエアフリーセミナー #yochiand
Takahiro Yoshimura
 

GroovyなAndroidテスト #atest_hack

Editor's Notes