テストカメレオン

ふと、購読中の配信情報見てみると、テストカメレオンなるテストサービスを見つけました。 TestChameleon !! 変幻自裁なアーキテクチャを持ってるのかな?とか、多様なサービス持っているのかな?と思いざっと読んでみました。機能自体は、SauceLabsやBrowserStackみたいなものですが、そのテスト実行環境のアーキテクチャが貼られていたところが個人的に面白かったです。 以下、画像は以下URLから引張てきています。おもしろそうだと感じた方は一読してみると良いかもしれません。 http://www.ministryoftesting.com/2015/03/automated-testing-cloud-testchameleon/ Architecture Selenium Hub使っているのですね。最近だと、iOSが絡むところ以外がEC2上などにブラウザ環境を構築できるようになってきたので、こういうテストサービス自体の価格や自動化の障壁も下がってきましたね。嬉しいことです。 Dashboard Documents https://dashboard.testchameleon.com/media/tech-docs/_build/html/ APIs https://dashboard.testchameleon.com/media/tech-docs/_build/html/technical_doc.html 所管 提供されるテストの記述がJavaの例だったのですが、Groovyやらでかけるようなラッパー用意すれば使いやすそう。RubyやGroovy、Pythonのような感じの、少ない記述でテストかける方が私は嬉しいな。 SauceLabsやTesetDroidのように、モバイルアプリ/モバイルWebのテスト環境が整っているサービスはやはりまだ少ない模様。一方、Web Browserの環境を提供するものは増えてきて価格競争に突入しそうな雰囲気がひしひしと伝わってきますね。 競争。。。More

モバイルアプリにおけるE2Eテストの自動化に関して少しまとめる

少し前に、雑にモバイルアプリのリリースサイクル毎で行っているテストの流れという記事を書きました。 考え方が少し変わったりしているのですが、そこからE2Eテストという枠を抜き出して、さらにはテスト自動化という文脈で少し話を整理してみようと思います。 ここでは、効率的なコード、失敗時の解析の容易さなどに対する言及は致しません。また、サーバ側に対するテストの話にはちゃんとは触れません。 E2Eテストに含まれる目的 モバイルアプリにおけるE2Eテストという言葉には、恐らく以下の目的(と雑なテストタイプ)が含まれていることが多いと思います。 アプリのGUIから操作した (もしくは表示される要素に対して直接操作した)という文脈を持ったうえでの、 シナリオテスト 想定したStoryやFeatureを含んだシナリオを用意し、そのシナリオを達成できるかを検証したい 機能テスト(システム全体) サーバ側機能を含んだ、モバイルアプリのGUIから操作して意図した通りに機能が単体で振る舞うかを検証したい シナリオとして複数機能をまたがって何かする、という所までは見ない 統合テスト サーバからの応答をえた上で、モバイルアプリのGUI上で描画される要素を検証したい サーバはモック/スタブサーバでも特に限定しない。モバイルアプリ自体を構成する機能を統合させた上で正しく動作するかを見るもの。 GUIテスト 画面の表示、ボタンは位置などのレイアウトに対するGUIのレイアウト崩れ、描画される要素の過不足を検証したい 画面サイズ、解像度、フォントサイズ、アクセシビリティなどを考慮 なお、4に関しては端末のガイドラインに準拠しているかといった内容や、ユーザビリティに対する話は含まれません。 自動化する時に検証する方法 目的4以外のものに関しては、多くはGUIからの操作なので入力に対する出力を得て、その出力に対してアサーションをとることで検証を行うことでしょう。 4のGUIテストに関しては、モバイルアプリの場合は必ずスクリーンショットをとる必要が出てくるでしょう。描画される要素の有無であれば不要ですが、レイアウトが期待通りか、という所まで検証しようとすると、要素が描画された上で確認しなければ正しい/正しくないの判断ができないためです。例えば、画面サイズや解像度の多様性により表示がおかしくなるというのはAndroid/iOSともに多く有ります。 どこまで検証するか GUIから操作するという文脈を持つテストの場合、多くは実行に時間を要します。そのため、どこまで、何を確認するかということで神経を使う必要があります。そこで、アプリをどこまで確認するか、というところで少し雑にまとめてみます。 なお、ここの分け方は検証したいことと、その環境で雑に区分しています。 1. シナリオテスト ユーザが実際に操作する内容をシナリオに落とし込んで、期待されるシナリオを完遂できるか検証する ユーザの操作が変わるパターンはなるべく用意する モック/スタブサーバは利用しない 外部システムとの連携、端末の設定に依存する箇所も含む 2. 機能テスト(システム全体) サーバ側からの応答によりモバイルアプリケーションの振る舞いが変わる場合、それは可能な限り網羅する GUIからすると同じ表示でも、その裏側(サーバからの応答)が異なる場合も含む 機能として仕様に定義した範囲 モック/スタブサーバは利用しない 外部システムとの連携、端末の設定に依存する箇所も含む 3. 統合テスト サーバ側からの応答によりモバイルアプリケーションの振る舞いが変わる場合、それは可能な限り網羅する GUIからすると同じ表示でも、その裏側(サーバからの応答)が異なる場合も含む モック/スタブサーバを用意してでも、サーバからの通信結果をもとに、アプリが期待通り動作することを検証することが目的 端末の設定に依存する箇所を含む 4. GUIテスト レイアウトパターンはなるべく網羅する 同一レイアウトの使い回しに関しては、不要なものは実施しない ツールとテスト モバイルアプリでは、Headless browserのようなGUIの無い高速な確認手段は存在しません。また、espressoや、Debug用にSDKとしてハックしたライブラリを使う以外は、システムが提供するアニメーションなど含めてそれらを許容した上で各種テストを回す必要があります。 そのため、基本的にGUIから操作した上で確認を行う必要があるため実行速度はWebアプリほど速度を出すことが難しいです。一方、espressoなどのように限定した使い方であれば安定して高速に確認する手段もそろってきたので、そこらへんも解消する日が来るかもしれません。 シナリオテストやGUIテストを目的としたE2Eのテストを行う場合、基本的にAppiumのようなGUI越しに操作するツールを使うことになるでしょう。そこでは実行速度と安定性がやはりトレードオフになります。一方で、現在のモバイルアプリを検証するツールとしてはこれ以上の手段は殆どないです。 機能テストや統合テストを目的としたE2Eのテストを行うときの多くもAppiumのようなGUI越しに操作するツールが基本になると思います。ただ、espressoのような高速にView単体を確認できる手段も選択肢としてでてきました。そのため、単なる表示のバリエーションなんかはAppiumのようなもので実施するよりも、遥かに高速に実施できる環境として利用できるようになってきました。 ここで話している文脈における自動化されたテストは、手動テストによる回帰テストを減らすことが目的で使うことが多いと思います。なので、互いに補完関係になるように、プロジェクトとして十分な目的を選んでいきたいですね。…More

Appiumのテストを1台の計算機上で並列して実行させる

Appiumでテストを実行していると複数台の計算機でテストを並列して実行したい、と思う方もいるでしょう。 Appium自体はサーバなので、1台の計算機上で複数起動させ、テストを並列して実行させることができます。これを行えば、独立したテストケースを分散させて、それぞれのテストを実行、結果を収集するという簡単なテストケースの実行並列化もできます。Selenium Gridよりもかなり手軽にテストを実行できる環境になるでしょう。 設定する点は以下 Appiumサーバに必要な引数を与えて起動する テストケース側のcapabilityに対象となるAppiumサーバの待ち受けポートを指定する 例えば、appium_libを使っている人だとcapabilitiesのportに値を設定する必要があります。 例 Appiumサーバの起動 ※appiumコマンド箇所は、適切にnode .などに置き換えてください capabilityの指定 例えば、appium_libを使っていると、appium.textの[appium_lib]にportを指定する方法があったり( ★ )、以下のように直接メソッドに値を与えるならserver_capsに対して要素を指定する方法があります。 いずれにせよ、これによりシナリオをAppiumサーバに渡すことができるようになります。 並列実行 Step1 Step2 以下2種類でそれぞれ起動 注意点 iOSではiOS Simulatorの制限上、複数Simulatorを同時に起動させることができません。そのため、iOSは並列実行するには物理的に複数のMacマシンが必要です。 ref: https://github.com/appium/appium/blob/master/docs/en/appium-setup/parallel_tests.md ref: https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/server-args.mdMore

JaSST15 Tokyoに参加、パネリストとして前に立ってきた

JaSST 15 Tokyoに参加してきました。 また、JaSST 15 Tokyoの企画セッションの1つである「Web.JaSST ~ウェブ開発のテスト~」で登壇してきました。 ※諸事情により、参加したのは2月20日だけです。 参加したセッション How To Get What You Want From Testing(for Testers, Developers, and Managers) テストプロセスの評価と改善 聞いた以外で面白そうだったセッション テストコードクリニック How To Get What You Want From Testing(for Testers, Developers, and Managers) Michael Bolton氏による発表です。 以下Twitterで簡単にまとめられていました。 同氏は、テスターがTestingの中心であると述べていました。そこに対して、TestingとCheckingの違いから、明らかな機能的な不具合の他に”おかしいと感じる”ことも重視してTestingするという話しを混ぜていました。 例えば、人は以下のような感情を受けます。これらは良くないものもあり、良くないと感じたらそこは不具合が存在する可能性が高い。それは今のところ機械では見つけられないTestingによって得られるフィードバック、ととれます。 Impatience Frustration Fear Suprise Confustion Annoyance Boredom Tiredness Anxiety これらの感情は、以下のような問題へと繋がります。 Capability Scalability Reliability Usability…More

AndroidJUnit4RunnerでParameterized Test

AndroidでもJUnit4が使えるようになったことで、parametarized testingも容易に可能になったのか確認してみました。 例 端末のローケルを設定し、その情報を取得する関数を確認するためのテストです。 コード テストコード 複数のローケルを設定した上で、正常に設定したローケルを取得できるか?というテストを愚直に書くと以下のようになります。 これ、多言語化が進むなどでlocalの設定する種類が増えると、そのぶんコピペのテストケースが増え、必要以上に冗長になります。 そこで、parametarized testです。 Parametarized test JUni4におけるParametarized Testの細かな構文説明はここでは除きます。 ポイントはざっと以下です。 RunWithでTheories.classを指定する ただ、本来はTheoriesは組み合わせテスト用… @DataPoint / @DataPointsでパラメータ化する要素をまとめる @Theoryにテストケースを書く @Testは使いません これにより、DataPointsを増やすだけでテストケースを増やすことが可能になります。 このDataPoint/DataPointsはBeforeが解釈される前に計算されるので、Beforeで設定した値を動的に入れるということはできません。 ちなみに、@Testとしてアノテーションを設定したら、通常のテストケースとして処理が行われます。 @Theoryは複数作っても良いので、たとえばLocalSettingParameterにより変わるテストケースを1つのファイルに集めて分散を防ぐとかもできます。 Androidのテスト、だいぶんまとめやすくなりましたね。More

DroidDriverなるものがあると知った

最近、AppiumのGitHub上でdroiddriverなるものを知りました。 https://github.com/appium/droiddriver これ、どこから来ているのか気になっていたら、どうやらgooglesource上から来ている模様。 https://android.googlesource.com/platform/external/droiddriver droiddriver_examplesを見てみたところ、このDroidDriverTestはActivityInstrumentationTestCase2を継承している模様。 ということは、ひとまずJUnit4の枠組みでも利用できますね。 ここを見ると、どうやらDroidDriverはSDKとしてはAPI21が必要らしい。確かに、先ほどのGoogleのコードを追っても、4.4(KitKat)以降開発され、まだ正式なものとして出てはなさそう。ただ、手元でDroidDriverを継承したテストケースをconnectedAndroidTestで回すと、4.2.2の端末でも動作したので、OS自体はuiautomatorを提供するものになるのかな。 API18以上はuiautomator driverだし、17以下はinstrumentation driverだし。 これはuiautomatorを拡張したdriverなのかもしれないですね。 ちなみに、DroidDriverを使うには以下のようにclassSetUpをOverrideする必要があるみたい。 手元で軽くespresso向けのテストをDroidDriver使って動かしてみると動作しました。 先にあげたGitHubに記載されている例の中には、例えば以下のようなメソッドがあるので、DroidDriverはespressoの代替ではなく、uiautomatorをJUnitから操作する枠組みな気がしています。 ともあれ、少し追ってみようかな。More

AndroidTestCase/InstrumentationTestCase/AndroidJUnit4のgetContext/getTargetContextを比べてみた

Androidのテストフレームワークにて使われる、getContext、getTargetContextで取得されるコンテキストの理解を整理するために以下のそれぞれに分けて比較してみました。得られるコンテキストはテスト対象のパッケージ、テストパッケージ(xxxx.testというパッケージ名になるやつ)の2種類のどちらかになるはずです。 AndtoidTestCaseを継承したテストケース InstrumentationTestCaseを継承したテストケース 何も継承しない(AndroidJUnit4で実施される)テストケース AndroidTestCase AndroidTestCaseでは、getContextでテスト対象のパッケージを得ることができるだけです。どうやら、AndroidTestCaseではsetTargetContextが@hideされているらしいです。そのため、テストパッケージはそのままでは取得できないらしいです。 参照 InstrumentationTestCase こちらは、getContextでテストパッケージ、getTargetContextでテスト対象のパッケージが取得できることがわかります。 AndroidJUnit4で実施されるテストケース こちらも、getContextでテストパッケージ、getTargetContextでテスト対象のパッケージが取得できることがわかります。 また、getInstrumentationが挟まることで何か大きく変わるのかと思いましたが、コンテキストの取得という意味では変わりないようです。そうですよね。 テストコードを理解するときは、そのテストで使われるコンテキストがなんなのかを理解することは大事なので、ここらへんの基礎的な理解はしっかり持っておきたいところですね。 参考 Testing Fundamentals http://developer.android.com/tools/testing/testing_android.html 2種類のパッケージがあることで、テストパッケージにテスト専用のリソースを配置(/resとか)して閉じた環境でテスト実行が可能になります。 蛇足 そういえば、最近 @FlakyTest と呼ばれるアノテーションを見つけました。不安定なテストのことを、Flaky testとよく呼びます。 1つめ: android.support.test.filters @Flakyは、テストのフィルタリングを行うためだけのアノテーション https://android-test-kit.googlecode.com/git/docs/javadocs/testing-support-lib-0.1-javadoc/reference/android/support/test/filters/FlakyTest.html 2つめ: android.test @FlakyTestは、テストが失敗したら勝手に再度トライしてくれるためのアノテーション http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.2_r1/android/test/FlakyTest.java?av=f This annotation can be used on an InstrumentationTestCase’s test methods. When the annotation is present, the test method is re-executed if the test fails.…More

android-test-kitで使われるInstrumentationRegistryの理解を深める

android-test-kitの理解を深めようと、以下を眺めていました。 https://code.google.com/p/android-test-kit/wiki/AndroidJUnitRunnerUserGuide この中で、JUnit4の枠組みの中でContextを取得するためのInstrumentationRegistryがどのように振る舞うのか気になったので少し追ってみました。 InstrumentationRegistry is an exposed registry instance that holds a reference to the instrumentation running in the process and it’s arguments and allows injection of the following instances: Androidのテストフレームワークは多くの方は既知だと思いますが、 ref: http://developer.android.com/tools/testing/testing_android.html のようになっていて、テスト対象のアプリケーションパッケージと、テストパッケージ、その間にInstrumentationTestRunnerが存在します。 android-test-kitを導入する前までは、このアプリケーションパッケージ/テストパッケージのコンテキストを取得するためには、テストケースのクラスがAndroidTestCaseもしくはInstrumentationTestCaseを継承する必要がありました。 一方で、android-test-kit導入すると、それらの継承なしでコンテキストを手に入れる手段があります。それがInstrumentationRegistryです。 いったん、このandroid-tets-kitが提供するAPI群を見てみます。すると、android.support.test配下にInstrumentationRegistryが提供されているのがわかります。 そのリファレンスを進むと、Public Methodとして以下が提供されていることがわかります。 getArguments() getContext() getInstrumentation() getTargetContext() registerInstance(Instrumentation instrumentation, Bundle arguments) おやおや。registerInstanceだけが先ほどのwikiで説明されていませんでした。となると、名前からしてもここが怪しそうです。registerInstanceの説明にも Records/exposes the instrumentation currently running and stores…More

Appium 1.3.5 released

Appium 1.3.5 がリリースされましたね。 リリースノート https://github.com/appium/appium/releases/tag/v1.3.5 ここまでのバージョンになると、開発量も少し落ち着いてきたように見えます。 iOS8.x系に関しても、iOS7=>iOS8のような大きな変更がシミュレータにも入るわけではないので。 driver.get()でpageを取得できなかったところなんかの修正が入っています。あとはiOS8.2。 iOS8.3もbetaで入手できるようになりましたが、iOS8.3からは OS X 10.10以降がRequirementになります。 なので、メンテナンスされるメインストリームもOS X 10.10に移り変わる流れになりそうな予感。 Androidに関しては以下の修正が入っているので、1.3.4使っている人は更新したほうが良さそう。もとより、私の環境では1.3.4があまりちゃんと動かなかったので、masterブランチや1.3.5betaを使っていましたが、ここでnpmから入手できる正式版が使えるようになった。 add workaround for issue where UiAUtomator fails to find visible elements. fixed undefined member error for the release object.More

UiSelectorを使うようにしたほうが良さそうだ

過去いったんまとめた、Appiumを使ってiOS/Androidの要素を取得する方法の数々に追記した。 Appiumの1.3.3まではできていて、1.3.5betaからできなくなったことに以下による要素の特定がある。 これは、以下のようにUiSelectorを使えば問題はないみたいだ。 UiSelectorはこちらから確認することができる。Uixxxxxシリーズは、uiautomatorの要素として提供されているものなので、UiSelectorをちゃんと使っていくという方がAndroidでは正しそう。 心無しか、AppiumもUiSelector使って安定したようにみえる。 Appiumで行うレベルのテストはテスト環境で影響される要素が多いので、地道にFlakyなテストを減らして安定したテストを回したい。。。More