Top Banner
Developers Summit 2012 実践 Android Developer Testing 12217日金曜日
78

実践Android Developer Testing

Aug 26, 2014

Download

Self Improvement

ussy

 
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 実践Android Developer Testing

Developers Summit 2012

実践 Android Developer Testing

12年2月17日金曜日

Page 2: 実践Android Developer Testing

Developers Summit 2012

本日のアジェンダと登壇者 テスト部の取り組みとテストレベル/自動化について松木 晋祐 @snsk Androidテスト部副部長 / NPO法人 ASTER 関連活動アジャイルプロセス協議会 テスト・レビューWG / ツールの活用を考える会他株式会社ACCESS 名刺に書いてないけど赤魔道士

テスト自動化ツールの紹介長谷川 孝二 @nowsprinting フリーランスの開発者。メインジョブはプログラマー、サブでテストとかサムライ(居合)とか。なかなかレベル上がらないのが悩み。

12年2月17日金曜日

Page 3: 実践Android Developer Testing

Developers Summit 2012

本日のアジェンダと登壇者 Model分離を用いたテスタビリティの向上持田 真哉 @mike_neck Android テスト部部員。株式会社トップゲート所属のプログラマー。Java、

Javascript、Groovyをやっています。以前所属していたSIerでの単体テストのあり方に疑問を持ち、テストの勉強を始めた。

ユニットテストの掘り下げ、SQLiteまわり吉澤 毅 @ussy00 Android テスト部部員。テスト部がシーンに放つ部屈指のメガネ男子。彼が部で披露するテクノロジーのプレフィックスには「オシャレ~」が付く鉄の掟がある。株式会社ヌーラボ ジョブはプログラマー

まとめと質疑応答全員

12年2月17日金曜日

Page 4: 実践Android Developer Testing

Developers Summit 2012

Androidアプリのテスト全般について 情報共有 情報発信

オープンプロダクトコミュニティにおける「ぶっちぎりのテスト力」をテスト部から世界へ

Androidテスト部(ATEC)ご紹介

12年2月17日金曜日

Page 5: 実践Android Developer Testing

Developers Summit 2012

主な活動

(だいたい)月1回のMTGで情報共有 Androidテスト祭り開催 ABCで講演/JaSST LT殴りこみ @IT連載「Androidアプリ開発入門」 メンバーが400人を超えました!

2012/2頭 時点で423名

12年2月17日金曜日

Page 6: 実践Android Developer Testing

Developers Summit 2012

最近の活動 ソースかつチーム

主に低層のテスト技術を調査 Androidアプリの開発者がテストしやすいように Androidアプリの品質を向上 翻訳・SDKのコードリーディング

ハッピーターンチーム 主に上層のテスト技術を調査 品質保証の観点からAndroidテストを考える Androidアプリの受入れガイドライン作成

Testterを主軸に検証 https://sites.google.com/site/

androidtestclub/testter

12年2月17日金曜日

Page 7: 実践Android Developer Testing

Developers Summit 2012

最近のホットなニュース

テスト部に予算がつきました! Sponsored by

@IT連載開始

CIサーバ調達しました!

12年2月17日金曜日

Page 9: 実践Android Developer Testing

Developers Summit 2012

本編

12年2月17日金曜日

Page 10: 実践Android Developer Testing

Developers Summit 2012

テストの段階「テストレベル」

テストレベル:組織的に管理されるテスト作業のグループ。テストレベルはプロジェクトの責任に対応するソフトウェアテスト標準用語集 v2.0.J01 より

12年2月17日金曜日

Page 11: 実践Android Developer Testing

Developers Summit 2012

受け入れテスト

システムテスト

結合テスト

単体テスト

通称:デベロッパーテスティング

通称:?

今日のお話は主にここ

テストの段階「テストレベル」

12年2月17日金曜日

Page 12: 実践Android Developer Testing

Developers Summit 2012

テスト自動化の3要素或いはテスト自動化とは何か?

Drive JUDGE Report

上記3要素のすべてを何らかの形で満たす必要がある。現在の主要なツールはほぼ全て満たしているが、どの部分がどの機能で満たされているのかを導入時に認識しておく

12年2月17日金曜日

Page 13: 実践Android Developer Testing

Developers Summit 2012

テスト自動化ツールの紹介

12年2月17日金曜日

Page 14: 実践Android Developer Testing

Developers Summit 2012

早速ですが、デモ

Robotium 主にView(GUIコンポーネント)を指定して操作

monkeyrunner 座標指定でタップ、ドラッグ

12年2月17日金曜日

Page 15: 実践Android Developer Testing

Developers Summit 2012

今すぐ使える!11のツール/フレームワーク

12年2月17日金曜日

Page 16: 実践Android Developer Testing

Developers Summit 2012

View操作系(1/3)

ActivityInstrumentationTestCase2 Android SDK内 android.testパッケージ。JUnit3

座標指定タップ、ドラッグも可能

Robotium ↑の拡張。Activity間の遷移を伴なうテストが可能

scirocco ↑の拡張。スクリーンショット、レポーティング

12年2月17日金曜日

Page 17: 実践Android Developer Testing

Developers Summit 2012

View操作系(2/3)

NativeDriver By Google. 2011/6リリース。ASL 2.0

テストコードはJUnitで記述

端末の回転、向きの取得、スクリーンショット

apkにserver-standalone.jarの埋め込み&起動が必要

WebDriver, NativeDriver for iOS

12年2月17日金曜日

Page 18: 実践Android Developer Testing

Developers Summit 2012

View操作系(3/3)

FoneMonkey By Gorilla Logic. 2011/11リリース。GPL v3

専用スクリプトを表形式のGUIで編集

実機でのrecording/playback

JUnitのコードにexport可能(独自TestRunner)

FlaxMonkey, FoneMonkey for iOS

12年2月17日金曜日

Page 19: 実践Android Developer Testing

Developers Summit 2012

座標指定系

monkeyrunner Android SDK同梱 テストコードはPythonで記述

スクリーンショット、画像比較による判定

ソースの中にmonkeyrecorder/playback.py

座標計算などのユーティリティをテスト部で作成

12年2月17日金曜日

Page 20: 実践Android Developer Testing

Developers Summit 2012

特殊なもの

Monkey Android SDK同梱 モンキーテスト(ランダムに操作)

SIKULI スクリーンショットからテストを書くタイプ PC向けだが、Androidエミュレータで利用可能

12年2月17日金曜日

Page 21: 実践Android Developer Testing

Developers Summit 2012

ユニットテスト向け

Android Testing Framework AndroidTestCase、ActivityUnitTestCaseなど @IT連載の第2回・第3回で紹介

AndroidMock EastMockのAndroid向けラッパー @IT連載の第5回(3月公開)で紹介予定

Robolectric JavaVM上でAndroidのテストを実行するもの

12年2月17日金曜日

Page 22: 実践Android Developer Testing

Developers Summit 2012

上層(GUI)テスト自動化の導入判断について

12年2月17日金曜日

Page 23: 実践Android Developer Testing

Developers Summit 2012

テスト自動化が有利

実行機会が多い 複数機種、複数Androidバージョン アプリの頻繁なバージョンアップ

特殊なテスト 並列処理テスト(連続タップ、同時タップ) 負荷テスト

12年2月17日金曜日

Page 24: 実践Android Developer Testing

Developers Summit 2012

テスト自動化が不利

自動テストの記述にコストがかかる Judgeまで自動化するのは難しい サーバとの通信、データベース

UIの変更が多く再利用できない 開発終盤や機能追加のたびにUIが変わる ActionBar対応を…強いられているんだ!

12年2月17日金曜日

Page 25: 実践Android Developer Testing

Developers Summit 2012

ここまでのまとめ

上層のテスト自動化は無理なく、 計画的に

下層のテストをより厚く この後、ノウハウを紹介します!

12年2月17日金曜日

Page 26: 実践Android Developer Testing

Developers Summit 2012

ユニットテストの導入

12年2月17日金曜日

Page 27: 実践Android Developer Testing

Developers Summit 2012

Androidアプリケーションのユニットテスト

• Activityだけでできているレガシーコードのアプリケーションにテストを付与する手順を説明します。

• なお、ここでレガシーコードというのは「テストのないコード」(マイケル・C・フェザーズ『レガシーコード改善ガイド』翔泳社)を指します。

12年2月17日金曜日

Page 28: 実践Android Developer Testing

Developers Summit 2012

AndroidのActivityのコード

onCreate(Bundle bundle) { // レイアウトのレンダリング // メッセージの処理 // データ処理 // ビューの表示(操作) // リスナーの割り当て}

12年2月17日金曜日

Page 29: 実践Android Developer Testing

Developers Summit 2012

AndroidのActivityのコード

onCreate(Bundle bundle) { // レイアウトのレンダリング // メッセージの処理 → C // データ処理 → M // ビューの表示(操作) → V // リスナーの割り当て → V / C}

12年2月17日金曜日

Page 30: 実践Android Developer Testing

Developers Summit 2012

AndroidのOnClickListenerのコード

onClick(View view) { // メッセージ取得 // データ処理 // ビューの表示(操作) // メッセージの送信}

12年2月17日金曜日

Page 31: 実践Android Developer Testing

Developers Summit 2012

AndroidのOnClickListenerのコード

onClick(View view) { // メッセージ取得 → C // データ処理 → M // ビューの表示(操作) → V // メッセージの送信 → V / C}

12年2月17日金曜日

Page 32: 実践Android Developer Testing

Developers Summit 2012

モデルが分離できていないActivityのコード例

Viewに関するコード

Modelのコード

Modelのコード

12年2月17日金曜日

Page 33: 実践Android Developer Testing

Developers Summit 2012

モデルが分離できていないActivityのコード例

http://goo.gl/YiH1w

12年2月17日金曜日

Page 34: 実践Android Developer Testing

Developers Summit 2012

Model - アプリケーションの核

• ロジック処理o データの規則を記述o データの整形

• データ永続化層へのアクセスo データの保存o データの取得

12年2月17日金曜日

Page 35: 実践Android Developer Testing

Developers Summit 2012

Androidアプリケーション時代の永続化層

• Database (SQLite3)• ネットワーク (SNSなど)• 各種センサー

o 加速度センサーo 温度センサーo GPS

12年2月17日金曜日

Page 36: 実践Android Developer Testing

Developers Summit 2012

アプローチ

• Activityに対するテストを記述してActivityを保護する

• テストの保護の上にモデルをActivityから分離して、モデルに対するテストを記述する

12年2月17日金曜日

Page 37: 実践Android Developer Testing

Developers Summit 2012

実際にテストを記述していく

• Modelの状態をViewによって確認する• ModelとViewが混在しているテスト• 不具合が確認された場合、ModelとViewの双方を確認していくことになる

12年2月17日金曜日

Page 38: 実践Android Developer Testing

Developers Summit 2012 12年2月17日金曜日

Page 39: 実践Android Developer Testing

Developers Summit 2012

初回実行時は成功する

12年2月17日金曜日

Page 40: 実践Android Developer Testing

Developers Summit 2012

二回目に実行すると失敗する

12年2月17日金曜日

Page 41: 実践Android Developer Testing

Developers Summit 2012

原因と対策

• 原因o データベースの状態に依存するテストになっている

• 対策o ActivityInsterumentationTestCase2<T

extends Activity>のsetUpメソッドにてデータベースを初期化する

12年2月17日金曜日

Page 42: 実践Android Developer Testing

Developers Summit 2012 12年2月17日金曜日

Page 43: 実践Android Developer Testing

Developers Summit 2012

再度実行してみるが落ちる

12年2月17日金曜日

Page 44: 実践Android Developer Testing

Developers Summit 2012

原因を探る• ActivityInstrumentationTestCase2<T extends

Activity>のgetActivityメソッドにてActivity onCreateとonResumeまで実行される。

• 起動後のActivityを元にDatabaseを取得して初期化する

• 起動後のActivityの状態からViewを取得して値を確認する

12年2月17日金曜日

Page 45: 実践Android Developer Testing

Developers Summit 2012

原因を探る• ActivityInstrumentationTestCase2<T extends

Activity>のgetActivityメソッドにてActivity onCreateとonResumeまで実行される。

• 起動後のActivityを元にDatabaseを取得して初期化する

• 起動後のActivityの状態からViewを取得して値を確認する

→異なるものを比較している!

12年2月17日金曜日

Page 46: 実践Android Developer Testing

Developers Summit 2012

回避方法

テスト内でもう一度onCreateメソッドを呼び出す

12年2月17日金曜日

Page 47: 実践Android Developer Testing

Developers Summit 2012

Threadが違うことに注意が必要

12年2月17日金曜日

Page 48: 実践Android Developer Testing

Developers Summit 2012

Activityと同じThread上でonCreateを呼び出すことで回避

12年2月17日金曜日

Page 49: 実践Android Developer Testing

Developers Summit 2012

Activityのテストによる保護が完成する

後はActivityのテストを落とさないようにModelに該当する部分を外部化していく

12年2月17日金曜日

Page 50: 実践Android Developer Testing

Developers Summit 2012

Modelを外部化した後のActivityのコード

12年2月17日金曜日

Page 51: 実践Android Developer Testing

Developers Summit 2012 12年2月17日金曜日

Page 52: 実践Android Developer Testing

Developers Summit 2012

Viewに関するコードModelのコード

12年2月17日金曜日

Page 53: 実践Android Developer Testing

Developers Summit 2012

ActivityInstrumentationTestCase2<T extends Activity>

• データから想定されるViewの結果を検証• ModelとViewが混在しているため、これはUnit Testとは言えない

• Modelに関するテストを行いたいが、ThreadやActivityライフサイクルに注意しなければならない

12年2月17日金曜日

Page 54: 実践Android Developer Testing

Developers Summit 2012

ActivityInstrumentationTestCase2<T extends Activity>

• データから想定されるViewの結果を検証• ModelとViewが混在しているため、これはUnit Testとは言えない

• Modelに関するテストを行いたいが、ThreadやActivityライフサイクルに注意しなければならない

12年2月17日金曜日

Page 55: 実践Android Developer Testing

Developers Summit 2012

テストをしていくにあたって

• Modelのテストを実施していくにあたって、ThreadやActivityライフサイクルに注意をはらうのはコストが高い

• コストの高いテストは実施されなくなるo テストのコスト×テスト実施頻度=一定値(テキトーな式です)

12年2月17日金曜日

Page 56: 実践Android Developer Testing

Developers Summit 2012

Androidアプリケーションにテストを挟み込むコツ

Activityからモデルを分離する!

12年2月17日金曜日

Page 57: 実践Android Developer Testing

Developers Summit 2012

ユニットテストの掘り下げSQLite まわり

12年2月17日金曜日

Page 58: 実践Android Developer Testing

Developers Summit 2012

テストデータの投入

@Overrideprotected void setUp() throws Exception { super.setUp();

helper = new AllowanceDatabase(new RenamingDelegatingContext(getContext(), "test_"));

SQLiteDatabase db = helper.getWritableDatabase(); try { db.execSQL("INSERT INTO ALLOWANCE_LOG(LOG_DATE, AMOUNT) VALUES(1320000000, 1000);"); db.execSQL("INSERT INTO ALLOWANCE_LOG(LOG_DATE, AMOUNT) VALUES(1330000000, 5000);"); db.execSQL("INSERT INTO ALLOWANCE_LOG(LOG_DATE, AMOUNT) VALUES(1340000000, 10000);"); db.execSQL("INSERT INTO ALLOWANCE_LOG(LOG_DATE, AMOUNT) VALUES(1350000000, 2000);"); db.execSQL("INSERT INTO ALLOWANCE_LOG(LOG_DATE, AMOUNT) VALUES(1360000000, 3000);"); } finally { db.close(); }}

SQL 文を記述

12年2月17日金曜日

Page 59: 実践Android Developer Testing

Developers Summit 2012

Fixture Library

テストデータセットアップ自動化 DBUnit (Java) ActiveRecord (Ruby) Test::Fixture::DBI (Perl) fixture (Python) Factory Girl (Ruby) ???? (Android)

12年2月17日金曜日

Page 60: 実践Android Developer Testing

Developers Summit 2012

Fixture for Android

SQLite Fixture Library https://github.com/ussy/sqlite-fixture

テストデータをファイルから投入 テスト専用 DB を作成 RenamingDelegatingContext

12年2月17日金曜日

Page 61: 実践Android Developer Testing

Developers Summit 2012

テストデータ

@Overrideprotected void setUp() throws Exception { super.setUp();

importData(FileType.Yaml, "AllowanceLogDataTest");}

テストデータ格納ディレクトリを指定

12年2月17日金曜日

Page 62: 実践Android Developer Testing

Developers Summit 2012

テストデータ---_id: 1LOG_DATE: 1320000000AMOUNT: 1000---_id: 2LOG_DATE: 1330000000AMOUNT: 5000---_id: 3LOG_DATE: 1340000000AMOUNT: 10000---_id: 4LOG_DATE: 1350000000AMOUNT: 2000---_id: 5LOG_DATE: 1360000000AMOUNT: 3000

12年2月17日金曜日

Page 63: 実践Android Developer Testing

Developers Summit 2012

Fixture Library まとめ

テスト専用データベースの自動 テストコードをみやすく 工夫することでテストを楽にできる

12年2月17日金曜日

Page 64: 実践Android Developer Testing

Developers Summit 2012

テストプロジェクトの罠

公開 API から、テストプロジェクトへのリソースへアクセスできない

リフレクションで取得している

12年2月17日金曜日

Page 65: 実践Android Developer Testing

Developers Summit 2012

マイグレーション

12年2月17日金曜日

Page 66: 実践Android Developer Testing

Developers Summit 2012

マイグレーション問題

確認作業が面倒 バージョンアップ作業を実機で確認?

クライアントならではの問題

12年2月17日金曜日

Page 67: 実践Android Developer Testing

Developers Summit 2012

DB 移行バージョン問題

12年2月17日金曜日

Page 68: 実践Android Developer Testing

Developers Summit 2012

解決案 各バージョンごとに SQLiteOpenHelper クラスを用意

https://github.com/ussy/android-dbtest

12年2月17日金曜日

Page 69: 実践Android Developer Testing

Developers Summit 2012

マイグレーションテストコードprivate Context context;

protected void setUp() { context = new RenamingDelegatingContext(getContext(), "test_");

helper = new SQLiteOpenHelperV1(context);}

public void testMigration() { helper = SQLiteOpenHelperFactory.get(context); // test code}

12年2月17日金曜日

Page 70: 実践Android Developer Testing

Developers Summit 2012

テストの自動化

12年2月17日金曜日

Page 71: 実践Android Developer Testing

Developers Summit 2012

CI

継続的インテグレーション ビルド、テスト、成果物生成を継続的に実行する

12年2月17日金曜日

Page 72: 実践Android Developer Testing

Developers Summit 2012

Jenkins

12年2月17日金曜日

Page 73: 実践Android Developer Testing

Developers Summit 2012

Android Emulator Plugin

自動ビルド、自動テスト エラー通知 APK ファイル生成 Android フラグメンテーション問題

解像度 OS バージョン

12年2月17日金曜日

Page 74: 実践Android Developer Testing

Developers Summit 2012

まとめ

12年2月17日金曜日

Page 75: 実践Android Developer Testing

Developers Summit 2012

デベロッパーテスティング心得

テストを楽にしていきましょう 不安なところを重点的にテストして、不安を取り除きましょう

Jenkins を導入して、自動化しましょう パッケージもつくらせて楽をしましょう

12年2月17日金曜日

Page 76: 実践Android Developer Testing

Developers Summit 2012

テスト自動化の3世代

Level1 Automation Record&Playback

Liner Script

Level2 Automation Data-driven Functional Decomposition

Level3 Automation Keyword Driven Model-based

TEST AUTOMATIONBODY OF KNOWLEDGE(TABOK) GUIDEBOOK Version 1.1

12年2月17日金曜日

Page 77: 実践Android Developer Testing

Developers Summit 2012

テスト自動化の3原則

受け入れテスト

システムテスト

結合テスト

単体テスト

1.上層にいくほどテスト自動化のコストと技術的ハードルが上がる

2.上層のテストはスコープが広いが欠陥までの距離が遠い。下層はその逆。

3.上層のテストは見た目の変化に弱い*1

下層のテストは「どう動くか」を保証しにくい

*1 と言われていたが第3世代の自動化ではこれを克服しつつある

12年2月17日金曜日

Page 78: 実践Android Developer Testing

Developers Summit 2012

ご清聴ありがとうございました。

12年2月17日金曜日