androidテスティング実践3 ユニットテスト・ci編
TRANSCRIPT
Androidテスティング実践
③ユニットテスト・CI編
本スライドは、NTTソフトウェア社内技術者育成研修(ソフト道場研修)テキストです。
【著作権・免責事項】
本セミナーコースの内容、本資料のすべての著作権は、NTTソフトウェア株式会社に帰属します。
無断での本資料の複写、複製、再利用、転載、転用を禁じます。
本資料と演習等で利用するすべての教材は、NTTソフトウェア株式会社からの保証なしに提供されます。
本書に記載されている会社名および製品名は、一般に各社の商標または登録商標です。
Copyright © 2016, NTT Software Corporation. 120
※ 演習問題に関するスライドは、一部を除き、本ファイルには含まれておりません。また、演習に必要なソースコードも含まれておりません。ご了承ください。
3. ユニットテスト自動化 ユニットテストについて
ツールの概要
ユニットテスト自動化で大事なこと
プロダクトコードのテスト容易性
「レガシーコード」改善
121Copyright © 2016, NTT Software Corporation.
Copyright © 2016, NTT Software Corporation. 122
ユニットテストについて
ユニットテストとは(1/2)
位置付け
開発者が安心するためのテスト(Developer Test)
プロダクトがデグレしないようにするためのセーフティネット
品質向上には寄与するが、品質保証が第一目的ではない
書くタイミング
プロダクトコードを書きながらテストも書くプロダクトコード完成後ではない
テスト対象
ビジネスロジック
開発者が実装していて不安なところ
画面(GUI)の試験は対象外とすることが多い
123Copyright © 2016, NTT Software Corporation.
ユニットテストとは(2/2)
テストを成功状態にしたままリファクタリングする
テストを失敗から成功に変化させるようにテスト対象コードを書く
テストを失敗させるテストコードを追加する
テストを失敗から成功に変化させるようにテスト対象コードを書く
失敗するテストコードを書く
Copyright © 2016, NTT Software Corporation. 124
(参考)TDD (テスト駆動開発)についてhttp://www.atmarkit.co.jp/ait/articles/1403/05/news035.html
プロダクトコードの「テスト容易性」
テスト容易性=テストが書き易いプロダクトコード
テストしたいロジックはActivityに書かない
(匿名)内部クラス禁止
リスナやAsyncTaskは普通のクラスにする。必要なものはコンストラクタで受け取れば良い。
テスト用にフィールドを差し替えられるように
「パッケージプライベート」なsetterやコンストラクタを必要に応じて用意。
テスト時にoverrideしたいメソッドをパッケージプライベートに。
「本来privateだがテストコードからはアクセスさせたいもの」は「パッケージプライベート」で。
テストはプロダクトと同じパッケージに置く。
Copyright © 2016, NTT Software Corporation. 125
「レガシーコード」改善
レガシーコード = テストが無いコードテストが無く仕様変更時に手がつけられないコード
レガシーコード改善自動ユニットテストでカバーしてから改造(変更)する
そのままだとテストが書けない場合テストが書けるように、必要最低限の改造をするデグレしないように、IDEのリファクタ機能を駆使する
(手動で変更しない)
フィールド/メソッド/クラス追加やアクセス修飾子変更はOK
参考書籍「レガシーコード改善ガイド」http://www.amazon.co.jp/dp/4798116831
126Copyright © 2016, NTT Software Corporation.
Copyright © 2016, NTT Software Corporation. 127
ツールの概要 Robolectric
Mockito
Robolectricの特徴
Android向けユニットテストフレームワーク
http://robolectric.org/
MIT License
Androidフレームワークの動作をJVMでエミュレーション
APIレベル16から21をエミュレート可能(3.0版現在)
実行速度が速い
Mockitoとの併用が可能
広い範囲のエミュレーションサポート
ビューの展開、リソース取得、データベース操作、etc.
とはいえ、JVM上のエミュレーションに過ぎないことに注意
128
ビジネスロジックの検証がメインとなるユニットテストでは十分使える
Copyright © 2016, NTT Software Corporation.
※http://robolectric.org/ よりロゴを引用
Robolectricのコンセプト
高速に実行できるLocal Unit Testの欠点(Android Framework APIが使えない)をRobolectricが克服
ユニットテスト・TDDで重要な「開発のリズムを損わないサクサクさ」でAndroid APIが絡んだ部分のテスト実行が可能になる
129Copyright © 2016, NTT Software Corporation.
local JVM (Java SE)
テストコード
JUnitなどAndroid Framework API
(空実装→Robolectric)
プロダクトコード
Robolectricの基本的な使い方(1/3)
基本はJUnit4
テストランナーを指定する(@RunWithアノテーション)
テストの前提条件を指定する(@Configアノテーション)
constantsの指定は必須(Robolectricがgradleの情報を得るため)
その他、エミュレートしたいAPIレベルの指定なども可能。http://robolectric.org/configuring/
130
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class)
Copyright © 2016, NTT Software Corporation.
Robolectricの基本的な使い方(2/3)
@RunWithと@Configをまとめて書くと
@Configは設定ファイルに書いても良い(おすすめ!)
ファイル名:src/test/resources/robolectric.properties
131
@Config(constants = BuildConfig.class)
@RunWith(RobolectricGradleTestRunner.class)
public class MyFirstRobolectricTest { .... }
constants=[パッケージ名].BuildConfig
Copyright © 2016, NTT Software Corporation.
Robolectricの基本的な使い方(3/3)
Shadowオブジェクト
AndroidフレームワークAPIの実装オブジェクト群
Androidフレームワークが提供するクラスと1:1対応
Shadowオブジェクトの使いみち
Androidフレームワークでは提供されていないAPIを提供
テストに有用な内部状態を知るためのAPIが中心
Copyright © 2016, NTT Software Corporation. 132
ImageView iv = (ImageView) activity.findViewById(.....);
ShadowImageView shadow = Shadows.shadowOf(iv);
ImageViewに対応するShadowオブジェクト
ShadowImageView shadow = Shadows.shadowOf(iv);
int resId = shadow.getImageResourceId();
本来なら不可能なImageViewの画像リソースIDにアクセス
Robolectricの制限事項(1/2)
Robolectric本体の制限事項
3.0版:API Level 21 (Android 5.0)までサポート
3.1版:API Level 23 (Android 6.0)までサポート
targetSdkVersion=23では動作させるためには、以下のいずれかの対応が必要※ https://github.com/robolectric/robolectric/issues/1932 参照
robolectric.propertiesに「sdk=22」と追記する
build.gradleのdependenciesに、以下を追記する。testCompile 'org.khronos:opengl-api:gl1.1-android-2.1_r1'
※compileSdkVersionとappcompat-v7のバージョンは同じでなければならない点に注意!
133Copyright © 2016, NTT Software Corporation.
Robolectricの制限事項(2/2)
134Copyright © 2016, NTT Software Corporation.
プロジェクトのbuild.gradleファイル
// (省略)
android {
// (省略)
compileSdkVersion 21
// (省略)
defaultConfig {
// (省略)
targetSdkVersion 21
// (省略)
}
// (省略)
}
dependencies {
compile 'com.android.support:appcompat-v7:21.
// (省略)
}
新規PJ作成時は最新verになっているのでcompileSdkVersionに合わせて修正
Mockitoの紹介
特徴
クラス定義から、そのクラスのスタブを生成できる
実オブジェクトの一部メソッドの動作を変更できる
MIT License
URLhttps://github.com/mockito/mockito (公式ホームページ)
http://goo.gl/pOFyaQ (公式ドキュメント)
http://tech.cm55.com/wiki/mockito/Manual (日本語紹介記事)
135Copyright © 2016, NTT Software Corporation.
※https://github.com/mockito/mockito よりロゴを引用
mockの概念
136Copyright © 2016, NTT Software Corporation.
Hoge mockHoge = mock(Hoge.class);
Hoge hoge = new Hoge();
例えば
で生成したmockHogeは
と違い
メソッドの戻り値を事前に定義したり
メソッドが呼ばれた事を後から確認したり
できる
spyの概念
137Copyright © 2016, NTT Software Corporation.
Hoge spyHoge = spy(new Hoge());
Hoge hoge = new Hoge();
例えば
で生成したspyHogeは
と同じ実装を持ちつつ
一部のメソッドの戻り値を事前に定義したり
メソッドが呼ばれた事を後から確認したり
できる
Mockitoの使い方
基本
モックの作成(mock)
メソッドの振る舞い変更(when, thenReturn, thenThrow)
メソッドが呼び出されたことを確認(verify)
実オブジェクトの振る舞い変更
spyオブジェクト生成(spy)
メソッドの振る舞い変更(doReturn, doNothing, doThrow)
公式ドキュメントのコード例参照
(1) Let's verify some behaviour!
(2) How about some stubbing?
(12) doReturn()|doThrow()| doAnswer()|doNothing()|doCallRealMethod() family of methods
(13)Spying on real objects
138Copyright © 2016, NTT Software Corporation.
Copyright © 2016, NTT Software Corporation. 139
【演習3-1】ユニットテスト環境構築 演習課題
ユニットテスト対応
Robolectricのテストサンプル作成
テスト実行
演習課題
以下作業を通じて、テスト環境構築の方法を習得してください。
Android Studio上でアプリを新規作成する
ビルドスクリプトを修正してRobolectric + Mockito対応にする
Robolectricのテストサンプルを追加し、実行してみる
Copyright © 2016, NTT Software Corporation. 140
ユニットテスト対応(Gradle)
141
// (省略)
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
// (省略)
testCompile 'junit:junit:4.12'
testCompile 'org.hamcrest:hamcrest-library:1.3'
testCompile 'org.robolectric:robolectric:3.0'
testCompile 'org.mockito:mockito-core:1.10.19'
// (省略)
} (挿入)必要なライブラリの宣言詳細は別途提示
Copyright © 2016, NTT Software Corporation.
Moduleのbuild.gradleファイル
Robolectricのテストサンプル作成(1/2)
以下のクラスを作成(テスト対象クラス:EditActivity.javaのクラス名の上でAlt+Enter→Create Test)
Copyright © 2016, NTT Software Corporation. 142
@RunWith(RobolectricGradleTestRunner.class)
public class MyFirstRobolectricTest {
private EditActivity activity;
@Before
public void setup() {
activity = Robolectric.buildActivity(EditActivity.class).create().get();
}
@Test
public void testSomething() throws Exception {
assertTrue(activity != null);
}
}
Robolectricのテストサンプル作成(2/2)
robolectric.propertiesファイル作成
Copyright © 2016, NTT Software Corporation. 143
constants=[パッケージ名].BuildConfig
コマンドラインからの実行
Instrumented Testを実行する場合(端末を接続した状態で)
Local Unit Test(今回のRobolectric)を実行する場合
Android Studioからの実行
テストしたいメソッドやクラスを選択して右クリック→[Run](Ctrl+Shift+F10) ※Preferences→keymap→Run context configuration
テスト実行
144
gradlew connectedAndroidTest
gradlew test
Copyright © 2016, NTT Software Corporation.
テストコードが緑になっている
(参考)Mavenのプロキシ設定
プロキシ配下で利用する場合は以下の設定も必要以下のディレクトリにsettings.xmlを配置するWindows系: c:¥Users¥ユーザー名¥.m2¥
settings.xmlの内容は以下の通り
Copyright © 2016, NTT Software Corporation. 145
<?xml version="1.0" encoding="UTF-8"?><settings>
<proxies>
<proxy>
<active>true</active>
<protocol>http</protocol>
<host>【プロキシのホスト名】</host>
<port>【プロキシのポート番号】</port>
</proxy>
</proxies>
</settings>
AndroidのHTTP通信ライブラリOkHttpのサブコンポーネントとして配布https://github.com/square/okhttp/tree/master/mockwebserver
Apache License Version 2.0
セットアップ方法build.gradleのdependenciesブロックに以下を記述
サーバの開始方法
Copyright © 2016, NTT Software Corporation. 146
testCompile 'com.squareup.okhttp:mockwebserver:2.7.5'
MockResponse response = ... (返して欲しいレスポンスを組み立てる)
MockWebServer server = new MockWebServer();
server.enqueue(response);
server.start();
URL mockServerUrl = server.url("/test").url();
URLのprefix(任意)を指定
(参考)MockWebServerについて(1/2)
(参考)MockWebServerについて(2/2)
MockResponse(返して欲しいレスポンス)組み立て方法
MockWebServer終了の方法(tearDown()で呼び出す)
プロキシ設定の無効化(MockServer開始前に呼び出す)環境により不要な場合もあり。環境への依存を下げるため書いておくのがベター。
Copyright © 2016, NTT Software Corporation. 147
MockResponse response = new MockResponse()
// JSONのContent-Type指定
.addHeader("Content-Type",
"application/json; charset=utf-8")
.setResponseCode(HTTPレスポンスコード)
.setBody(HTTPレスポンスボディ);
server.shutdown();
System.clearProperty("proxyHost");
System.clearProperty("proxyPort");
Copyright © 2016, NTT Software Corporation. 148
テスト対象アプリの解説
Copyright © 2016, NTT Software Corporation. 149
【演習3-2,3】ビジネスロジックのテスト
Copyright © 2016, NTT Software Corporation. 150
【演習3-4】イベントリスナのテスト
Copyright © 2016, NTT Software Corporation. 151
【演習3-5】HTTP通信を伴うメソッドのテスト
Copyright © 2016, NTT Software Corporation. 152
【演習3-6】データベースアクセスのテスト
4. CIの実現 CIの概要
Android開発プロジェクトに適用する
(参考)Instrumented Testも実行する場合
Copyright © 2016, NTT Software Corporation. 153
CIとは
継続的インテグレーション(Continuous Integration)
自動的に以下を実施してくれる
リポジトリから最新のソースコード一式を取得
ビルドや自動テストなど実行し、その結果を通知
Copyright © 2016, NTT Software Corporation. 154
通常は専用のサーバで動かす
CIのメリット
ビルド・テストに失敗するコードがコミットされたときに、いち早く検知し、対策を打つことができる。
Androidのように、ビルドや全テスト実行に時間がかかる場合でも、CIサーバに全てお任せすれば、生産性向上につながる。
Copyright © 2016, NTT Software Corporation. 155
Jenkins
概要
広く使われているCIサーバhttps://jenkins.io/
MIT License
特徴
インストールが簡単
コマンドライン1行でOK (java -jar jenkins.war)
yumやapt-getでインストールすることも可能
設定が簡単
全てWeb画面から設定できる
Copyright © 2016, NTT Software Corporation. 156
※https://github.com/jenkinsci/jenkins よりロゴを引用
Android開発プロジェクトに適用する
前提条件
Android StudioとGradleでプロジェクトが構築されていること
ソースコードがSubversionやGitで管理されており、CIサーバからチェックアウトできること
この研修で実現できる項目
ビルド結果
Android Lint結果
Local Unit Test結果
この研修では概要のみ触れる項目
Instrumented Test結果(エミュレータの起動が不安定、実行時間が非常に長くなるなどの問題があるため、導入には試行錯誤が必要)
Copyright © 2016, NTT Software Corporation. 157
Android開発プロジェクトに適用する
プラグインのインストール[Jenkinsの管理]→[プラグインの管理]
(★)Android Lint Plugin
Gradle plugin
Subversion plugin(ソースコードリポジトリがSubversionの場合)
Git plugin(ソースコードリポジトリがGitの場合)
JUnit plugin
Copyright © 2016, NTT Software Corporation. 158
※ Jenkins 2.0からは、セットアップ時に「Suggested Plugins」を選択
していれば、★印のプラグインのみインストールすればOK
Android開発プロジェクトに適用する
[Jenkinsの管理]→[システムの設定]
[Jenkinsの管理]→[Global Tool Configuration]
原則デフォルト設定のままでOK
既にインストールされているJDKやgitなどを利用したい場合はそのパスを指定しても良い。
Copyright © 2016, NTT Software Corporation. 159
Android開発プロジェクトに適用する
新規ジョブ作成
「フリースタイル・プロジェクトのビルド」を選択
ソースコード管理
SubversionかGitを選択し、リポジトリのURLなどを入力
ビルド・トリガ
お好みで。迷ったら「SCMをポーリング」で良い
ビルド
[ビルド手順の追加]→[Invoke Gradle script]
[Use Gradle Wrapper]を選択
Tasksに[clean lint testDebugUnitTest]と入力
ビルド後の処理
[ビルド後の処理の追加]→[Publish Android Lint results]([Lint files]は空欄でOK)
[ビルド後の処理の追加]→[JUnitテスト結果の集計][テスト結果XML]に[app/build/test-results/debug/*.xml]と入力
Copyright © 2016, NTT Software Corporation. 160
(参考)Instrumented Testも実行する場合
[Jenkinsの管理]→[プラグインの管理]
Android Emulator Pluginをインストールする
ジョブの設定
[ビルド環境]→[Run an Android emulator during build]にチェック
起動したいエミュレータの情報を入力
[Common emulator options]→[Show emulator window]はチェックしない
[Invoke Gradle script]→[Tasks]
[connectedAndroidTest]を追加
[ビルド後の処理]→[JUnitテスト結果の集計]
[テスト結果XML]を[app/build/**/TEST*.xml]に修正
Copyright © 2016, NTT Software Corporation. 161
まとめ
Copyright © 2016, NTT Software Corporation. 162
この研修で説明したこと
自動テストについての考え方
Androidのテストツール基礎知識
Local Unit Test, Instrumented Test, ATSL, ...
システムテスト自動化ツールの使い方
Robotium, Espresso, UI Automator, Appium
ユニットテスト自動化ツールの使い方
各種テストは以下のテクニックを駆使して実現する
Android Studioのリファクタリング機能
テスト用のメソッド・コンストラクタの追加
Mockitoのmock()とspy()
MockWebServer
CIの実現方法
Copyright © 2016, NTT Software Corporation. 163
最後に
プロダクトコードを自動化したユニットテストでカバーすることで、ソース修正時の安心感が劇的に上がります。
既にレガシーコードがある場合は、全部やろうとせず、CIやユニットテストから少しずつ始めて行くと良いでしょう。
テストが全く無くても、CIだけ始めてみる。
Android Studioに移行するだけで始められます。
新しく機能追加したところだけでもテストを書いてみる。
リリースを何度も行うプロジェクトでは、システムテスト自動化にもチャレンジしてみてください。
Copyright © 2016, NTT Software Corporation. 164
おわりお疲れ様でした
https://www.ntts.co.jp/products/soft_dojyo/index.html