sansan における android アプリ自動テスト導入事例
TRANSCRIPT
Robotium を使ったAndroid アプリ自動テスト導入事例
2016/03/23 Android Testing Bootcamp#1Sansan 株式会社 辰濱健一
Robotium を使ったAndroid アプリ自動テスト導入事例
2016/03/23 Android Testing Bootcamp#1Sansan 株式会社 辰濱健一
Sansan におけるAndroid アプリ自動テスト導入事例
2016/03/23 Android Testing Bootcamp#1Sansan 株式会社 辰濱健一
Sansan におけるAndroid アプリ自動テスト導入事例
2016/03/23 Android Testing Bootcamp#1Sansan 株式会社 辰濱健一
DroidKaigi RejectConf の完コピの予定でしたが、内容変更しました!!
Sansan におけるAndroid アプリ自動テスト導入事例
2016/03/23 Android Testing Bootcamp#1Sansan 株式会社 辰濱健一
実は、既に自分の中ではRobotium オワコン…
>Agenda
6
• 自己紹介
• なぜ Robotium ?
• テスト記述のポリシー
• 実行環境
• デモ
• 自動テストを導入してみて
• Appium で iOS とコードの共通化
• UI テストで他にもできそうなこと
• これから
自己紹介
7
>自己紹介
8
• 辰濱健一 @tatsuhama50• https://www.facebook.com/kenichi.tatsuhama• http://www.slideshare.net/kenichitatsuhama
• 徳島県生まれ、徳島県勤務
• Tokushima.app というスマホアプリ勉強会を主催
• 趣味は音楽&旅行
>自己紹介
9
• 業務経歴
• 1 社目@徳島市
• Java, C++, MFC• UWSC を使った Windows アプリの UI 自動テストの導入
• 性能改善チームにて、自動性能計測ツールを作成
• 2 社目@徳島市
• iOS ( Objective-C ) , Android ( Java ) , Windows ( C# )のスマホ&タブレット向けアプリ開発
• 機能担当制、 iOS で作った機能は作った人が他 OS に移植
• 3 社目@徳島県神山町
• スマホアプリの自動テスト
• リモートワーク
開発&品質担保と自動テスト
モバイル開発
モバイル開発での品質担保と自動テスト
>Sansan 株式会社
10
モバイルアプリエンジニアは、 2 つの事業部で 8 人のメンバー
・ Sansan … 4 名( iOS x2 / Android x2 )
・ Eight … 4 名( iOS x2 / Android x2 )
- もう紙の名刺はいらない!
- 「超音波」等で周囲の Eightユーザーを検索
- 複数のユーザー間でも名刺交換ができる
- まずはアプリで+ボタンを!
11
>Eight の新機能「オンライン名刺交換」
12
>それでは
Eight のアプリを起動して、
「+」→「名刺交換」
→ 「近くのユーザと名刺交換」
画面をタッチ
で名刺交換してみましょう!
QR コードでもできるよ。
>Sansan 神山ラボ
13
• 築 70 年の木造古民家( 3 棟)
• 略歴
• 2010 年設置
• 〜 2013/11: 合宿所
• 2013/11 〜 : 常駐メンバーのいる開発拠点に
• 家具家電、畑付き、風呂トイレセパレート
• 家賃:数万円 / 月
• インターネット接続:光回線
• 最寄り駅まで徒歩 15 分
• 改装 OK 物件
>Sansan 神山ラボ
14
本題に入る前に…
15
>本題に入る前に…
16
• UI テストは、ユニットテストに比べて、ものすごく時間がかかります。• コミット毎の UI テスト実施は現実的じゃないです
• デイリーやリリースごとがオススメ
• 本セッションは、 UI テストのノウハウや弊社における導入事例を紹介します
• 導入する費用対効果は、プロダクトによってまちまちだと思うので各自で判断下さい
なぜ Robotium ?
17
>スマホアプリの自動テストライブラリ
18
Android 専用RobotiummonkeyrunnerEspressoUI Automater など…
iOS 専用KIFKiwiなど…
ハイブリッド
AppiumCalabashMonkeyTALKなど…
>Robotium にした理由
19
• Android 実装と同じ Java 言語で記述
• アプリケーション内部のオブジェクトを参照できる
• UI に見えない内部の値、 Activity の getter を呼べるSharedPreference の値
• DB にもアクセスできるので期待値や操作を動的生成できる→ サーバ DB 状態の変更にも強い
• ただし、リリースビルドでは使えない
• 導入当時( 2014/05 )、最終局面で Espresso とどっちにするか悩んだ。
•
>Robotium にした理由
20
• Android 実装と同じ Java 言語で記述
• アプリケーション内部のオブジェクトを参照できる
• UI に見えない内部の値、 Activity の getter を呼べるSharedPreference の値
• DB にもアクセスできるので期待値や操作を動的生成できる→ サーバ DB 状態の変更にも強い
• ただし、リリースビルドでは使えない
• 導入当時( 2014/05 )、最終局面で Espresso とどっちにするか悩んだ。
• 今となっては、 Espresso にしておけば良かったと思う…。
>Robotium にした理由
21
• Android 実装と同じ Java 言語で記述
• アプリケーション内部のオブジェクトを参照できる
• UI に見えない内部の値、 Activity の getter を呼べるSharedPreference の値
• DB にもアクセスできるので期待値や操作を動的生成できる→ サーバ DB 状態の変更にも強い
• ただし、リリースビルドでは使えない
• 導入当時( 2014/05 )、最終局面で Espresso とどっちにするか悩んだ。
• 今となっては、 Espresso にしておけば良かったと思う…。
• 判断当時メンテが最新の方を採った。 Espresso の方が便利!
テスト記述のポリシー
22
>テスト記述のポリシー
23
• ライブラリとテストコードの結合度を下げる
• まずは、浅く・広く記述する
• あきらめも大事
• 待ち方のコツ
• どの環境でも動くように
テスト記述のポリシー
ライブラリとテストコードの結合度を下げる
24
>ライブラリとテストコードの結合度を下げる
25
• 目的
• テストコードの可読性を上げる
• ライブラリに依存しないテストコードにする
• ライブラリにない機能追加ができる
• 実行ログの記録
• エラー時にスクリーンショットを残すようにする
• 理由
• ライブラリの API 変更 , ライブラリの置き換えでテストコードの修正が伴わない
• 失敗時の原因調査がしやすい
>Robotium Getting Started は密結合
26
• https://github.com/RobotiumTech/robotium/wiki/Getting-Started
• あくまでも API の使い方と思っておきましょう。
• 【対応】テストの基底クラスなどを作って clickOnText(String) を作り、テストコードではそちらを呼び出す
テストコードとライブラリが密結合
>ライブラリの依存性排除
27
• ライブラリの隠蔽
Robotium 版
>ライブラリを置き換えるとしても…
28
• テストコードを修正することなく、対応可能
Robotium 版
Espresso 版
※Robotium と Espresso は同じ InstrumentationTest なので、共存可能!!
テスト記述のポリシー
まずは、広く・浅く記述する
29
>まずは、広く・浅く記述する
30
• 背景
• スマホアプリの UI や機能は比較的すぐ見直しが入る
• 使えないと致命的な機能と、そうでない機能がある
• 対策
• まずは、費用対効果の高い、主要機能のワンパスを通す
• ログイン → 検索・閲覧・編集 → ログアウト あたり
• ログイン時のバリデートチェックよりも、ログインできるかの方が重要
• 慣れてきたら、各画面の詳細テストへ
テスト記述のポリシー
あきらめも大事
31
>あきらめも大事
32
• 別アプリと連携するものなどは手動で確認へ
• 例)
• カメラのピントが合っていること
• 住所文字列をタップすると地図アプリが起動し、その場所にピンが立っていること
• URL をタップするとブラウザが起動し、ページが正しく表示されること
• 場合によってはアプリ選択画面が出る
• 起動後の状態判定は目視の方が容易
• こういう所の自動化を頑張るのは費用対効果的に微妙…
>あきらめも大事
33
• 例) URL をタップするとブラウザが開く
アプリ ブラウザ
>あきらめも大事(だけど、知見共有)
34
• 例) URL をタップするとブラウザが開く
• Robotium や Espresso は UI 操作により別アプリが開くと、その後どうしようもなくなる…
• 理由
• アプリケーションの操作であって、端末の操作ではない
• 対応策
• UI Automater と 併用する
• ※但し、 minSdkVersion に注意
• このあたりは、 TOYAMA Sumio 氏の発表に委ねます
• Espresso の Intent チェックを使う
>あきらめも大事:メールチェック編
35
• 別アプリ…とはいえ、送られてきたメールをチェックするなら、MailCatcher & MailCatcher API で実現可能
• MailCatcher• SMTPサーバを経由したメールをブラウザから確認できる。開発中の誤送信防止にも役立つ。
• http://mailcatcher.me/
• MailCatcher API• /messages• /messages/:id.json• /messages/:id.html• /messages/:id.plain
など
>あきらめも大事:メールチェック編
36
• Retrofit & RxAndroid を使えば容易
• 指定したタイトルのメールが届いているか?
• 特定のメールを開いて本文の URL をタップ(メール本文から URL を抽出して、 OkHttpClient などで post する)
※Message モデルのプロパティは 一部しか宣言していない
テスト記述のポリシー
待ち方のコツ
37
>待ち方のコツ
38
• テストコードでは SLEEP 関数は使わない
• 自作関数やライブラリのラッパー関数内で使うのはアリ
• 端末、実行環境、サーバの状態によって待ち時間は違う!
• どうするか? → wait* 関数を使う
• ライブラリ関数の例
• waitForActivity• waitForFragmentByTag• waitForCondition
テスト記述のポリシー
どの環境でも動くように
39
>どの環境でも動くように
40
• 操作手順や期待値の動的生成
• エミュレータ判定
• 多言語対応
>どの環境でも動くように
41
• 操作手順や期待値の動的生成
• エミュレータ判定
• 多言語対応
>操作手順や期待値の動的生成
42
• 弊社の開発事情によるところかも知れないですが…「開発用」「ステージング」「本番」でデータセットが異なります。
• 検索結果などが保証されるためにも
• ローカル DB を参照して操作手順や期待値を動的生成する
• ログイン後にテストコードでデータを作る操作を行う
• このデータに対し、検索・編集・削除などのテストを行う
• ノイズにならないためにログアウト前に作ったデータを削除する操作を行う
• これにより、環境非依存なテストケースになります
>操作手順や期待値の動的生成
43
実際のテストコード
myName : ” 山田賢治”
users : {Uesr(阿部拓真 ), User(浅野緋美 ) , User(葉加瀬万太郎 ), …}
※ログインユーザを変えると、 myName は違う値※ログイン企業を変えると、 users も違うデータセットが返る
>どの環境でも動くように
44
• 操作手順や期待値の動的生成
• エミュレータ判定
• 多言語対応
>どの環境でも動くように
45
• エミュレータかどうかの判定
• 実機じゃないと確認できない項目(カメラなど)はこのフラグを見てスキップさせる
>どの環境でも動くように
46
• 操作手順や期待値の動的生成
• エミュレータ判定
• 多言語対応
>多言語対応
47
• https://github.com/RobotiumTech/robotium/wiki/Getting-Started
• ↑あくまでも API の使い方と思っておきましょう。
• 【対応】
• Robotium なら、 clickOnText(@StringRes int) を作って、 getString(…)
• Espresso なら、 withText に @StringRes int を渡す
日本語の時文言が違えば、このコードはエラーになる
※表示文言が仕様通りであることの判定にはならないので要注意
実行環境
>実行環境
49
• 基本的に実機で実行
• 昔は Jenkins & エミュレータでやっていた
• テストが増え、 CI 環境を長時間( 2h 以上※)占有する&エミュレータが不安定なためやめた• ※無料版、有料版など全パターン回した場合
• jacoco でカバレッジ計測
• どこのテストが足りてないかわかる
• 開発環境 DB で実施
• 固定のデータセット、特定のデータを使いたい場合は Docker にて特定のデータセットを持つ DB を用意
>Jacoco のカバレッジレポート
50
• html で出力される(抜粋)
• 2016/02 時点で 59% をカバーできている
>Jacoco のカバレッジレポート
51
• html で出力される
• 通っていないパスがよくわかる
>Docker を使った固定データ環境
52
• 開発環境(データや件数が他者によって書き換えられる可能性があ
る)でもテストが行えるようにしているが、以下のニーズがある
• パフォーマンス計測がしたい(ので、件数固定じゃないとダメ)
• テスト用に特定のユーザセットが欲しい• 例)アカウント停止ユーザのエラーチェック
• アプリからは設定できないデータを持つ名刺が欲しい• 例)名刺交換日未設定
• ローカル DB をアテにしない期待値を書きたい• 例)山田賢治さんは○○枚名刺を持っている
• Docker で環境( API&DB )のイメージを持っておき、テストコードから環境準備&片付けを行う
>Docker を使った固定データ環境
53
• 事前準備
• Jenkins に環境起動用のジョブ / 環境破棄用のを作成
• テスト実行時
• setup() で 環境起動用の Jenkins ジョブを Jenkins WebAPI を用いて実行
• アプリの API の向き先を差し替える
• テスト実行中
• 起動した環境に接続してテストを実施
• テスト終了時
• tearDown() で環境破棄用の Jenkins ジョブを Jenkins WebAPI を用いて実行
• API の向き先を戻す
デモ
>デモ動画
55
• 2014/11 時点の動画です
• http://youtu.be/scY_RPgfxeY• 4 分ぐらいありますが、発表時間の都合上ちょっとだ
け…
自動テストを導入してみて
>自動テスト導入してみて
57
• デグレードがないことを容易に確認できる
• メンテは思ったほど大変じゃない
• コツ: 1 行で書ける画面操作も clickSendButton() などの関数にして共通利用するとよい
• テストでしっかりカバーしていれば、大規模なリファクタリングも安心!• これから、通信ライブラリ・カメラ API ・デザインパーツの差し替え・ DB の置き換え?などが控えている
• モックを使わないので、サーバの動作確認にもなる
• 同じ仕様の iOS アプリもテストしたい…
>自動テスト導入してみて
58
• デグレードがないことを容易に確認できる
• メンテは思ったほど大変じゃない
• コツ: 1 行で書ける画面操作も clickSendButton() などの関数にして共通利用するとよい
• テストでしっかりカバーしていれば、大規模なリファクタリングも安心!• これから、通信ライブラリ・カメラ API ・デザインパーツの差し替え・ DB の置き換え?などが控えている
• モックを使わないので、サーバの動作確認にもなる
• 同じ仕様の iOS アプリもテストしたい…
Appium で iOS アプリとテストコードを共有する
>Appium
60
• http://appium.io/• iOS アプリでも Android アプリでもテスト可能
• リリースバイナリでもテスト可能• 但し、アプリ内部オブジェクトにはアクセスできない…
• Java, Ruby, JavaScript などで記述可能
>設定ファイル( 1/2 )
61
>設定ファイル( 2/2 )
62
>デモシナリオ
63
タップ 入力 エラー
>テストコード
64
iOS アプリの View のアクセシビリティラベ
ルに Android と同様のView ID を付与してい
るのがミソ
>実行するコマンド
65
- Appium 起動
> appium &
- for iOS> OS=iOS rspec spec/signup_spec.rb
- for Android> OS=Android rspec spec/signup_spec.rb
- スクショ一覧作成(オレオレ Ruby ツール)
> cd screenshot> ruby collector.rb
同じ!
デモ
>スクショ一覧( Android & iOS8 )
67
>スクショ一覧( Android & iOS9 )
68
iOS9だと、スクショで一部 View が欠落する…
> Some elements are invisible on screenshot of iOS 9.2
69https://github.com/appium/appium/issues/6229
Appium の話は終わり。
Appium の話は終わり。
Appium 遅いね。。。
UI テストで他にもできそうなこと
(ちょっとだけ着手して、本格導入できていない件)
>推移時間(イメージ)
73
• パフォーマンス改善の結果確認、性能デグレの検出ができる(かも?)
• 通信状態やサーバ状態に大きく左右される気がする…
>通信回数の分析
74
呼び出し毎に API 名と実行時間を csv ファイルに出力
Excel のピボットテーブルで集計
iOS / Android で同じ仕組みを入れれば、同じ操作で API 呼び出しの違いがわかる!
そんなに呼び出す必要あるの…?
サーバ負荷削減のためのボトルネック分析が容易になる
Excel マクロ
>通信回数の分析(推移)
75
さっきのデータを実行毎に集計する呼び出し回数削減施策導入
>スクショ一覧
76
画面名→
画面名→
画面名→
Nexus4 Nexus5 デザイン指示画像(期待値)
※元サイズが違うけど、 今は同じサイズで 表示されている
目で比較する!
デザイナのチェックや意図しないレイアウト崩れの確認が楽になりました
これから
>これから
78
• Espresso も併用して、 Robotium ではテストしづらかった部分のテスト( Intent のチェックなど)を行う
• UI Automater も併用して、
• アクティビティを保持しない設定にする
• 最小化&復帰後の画面状態のテスト
• AWS Device Farm を使って、所有していない端末を時間借りしてテストを行う
• Device Farm も Appium をサポートしている!※但し、まだ Java 記述のみ…
• http://www.slideshare.net/kenichitatsuhama/device-farm
まとめ
>まとめ
80
• 頑張ればいろいろできる
• 少人数でやっていれば影響範囲はわかるので、導入は各自判断ください…
• 頑張りすぎない、広く浅くから!
• 色んな機種でスクリーンショット集めるのはオススメ
• 色んなライブラリを組み合わすことも可能
質疑応答
ステッカー欲しい方はお声がけ下さい!!