Edited at

BitriseでReactNativeのEspressoUITestを走らせてみた話(Android編


BitriseでReactNativeのUITestを走らせてみた話

AutoScale,Inc.でアプリの運用から開発をやっている@t0m0120です!

前回のレビュー施策に引き続き今回はReactNativeTokyo#6で登壇させていただいた際のスライドReactNativeアプリをBitrise上でUITestしてみた話の詳細記事という感じです。

長すぎたので一旦Androdのみにしました

WF-1000XM3ノイキャンやばすぎて集中力30%ぐらいバフされてる気がします。


そもそもなぜUITest走らせたくなったのか


  1. iPhone/Android端末多すぎ問題


    デザインの修正などいちいち確認するのが面倒だけど崩れとか最低限よく使われる端末は安定させたい。


  2. NativeBaseのButtonにtransparent使っていると32bit(?)で落ちる問題


    多分32bit?のAndroid端末でクラッシュしていたみたいで気をつけていなかったのもあるがリリースしてしまった。32bit端末のシェアも少ないがレビューの☆1で気づき数時間で修正pushできたから良かったが事前に防ぎたい。今後はAndroidアプリも審査3日間かかるなど危険そう。

    Button.js theme backgroundColor: null crashing on RN 0.59.1 Android NoSuchKey Exception: backgroundColor #2673


という2点の理由から事前に気づける環境がない事が悪いと思い

UITest走らせたいなーReactNativeTokyoのLTネタになるしなと思い1週間ぐらいかけてUITestをBitrise上で走らせてみた。


まず技術採用


テスト走らせる場所として

AWS Device Farmが会社でポイントがあり使ってみたが実際にapkをアップロードしてブラウザ上で実機を動かせたりして便利だったがポイントがあるとはいえ高いというのとremote accessに32bit端末が無くprivate_deviceを使うにはお問い合わせが必要だったので保留

(今後特定の端末でのバグを実機でちょっと触りたいなという場面が来たらremote_accessで使いそう

次にFirebase TestLabを候補にあげた。が

image.png

無料枠だと1日5件か10件

デバイスだと1時間1~5$と毎日走らせたりビルドのたびに走らせてチェックするにはちょっとお金かかりそうかなーと思っていたところに

普段使っているBitrise上に

DeviceTestingAndroid



DeviceTestingIOS

を発見

Bitriseを使っていれば特に金額もかからずBitrise経由でTestlab叩いているっぽい。

対応端末も


Android

image.png


iOS

image.png

と見た感じ一番小さいiPhoneSE ノッチありiPhoneX

Android32bitのNexsus4と割と新しめにPixel2

があり最低限は確保されている感じがしたのでこちらを使ってみることにした。

最終的には普段はBitriseでUITestを常に走らせておいて

リリース前にBitrise build -> apkをTestLabにscriptでUPload

物理デバイス5台をテストしておくみたいな体制になりそう。

ちなみにSocialDogではBitriseはOrgStandard(約1万円)を使っています。

基本的にDeveloperでも大丈夫な気がしますがインターン二人と僕がデザイン系のタスクすると大渋滞起こしたり時々45分の制限を超えたり2個並列してビルドすると待ちあんまりないなーとOrgにしています。

(1マシン45分→2マシン90分)

image.png


テストコードを書く


ReactNative

<LoginButton

testID='LoginButton'
accessible,
accessibilityLabel='LoginButton'
>

// 実際は
<LoginButton
{...set_id('LoginButton')}
>
// でReleaseBuildはnull開発系でiOSはtestID/Androidはaccessibilityみたいにしてる。

上のように遷移するボタンに一通りtestIDaccessible, Labelを追加しておく。


Android

一番メジャーそうかつTestLabで押されているEspressoを採用しました。

Espresso setup instructionsの通りにTest周りの依存関係を入れてからテストファイルは作成せずに

EspressoTestRecorderのとおりにAndroidStudioからアプリを立ち上げた状態でTestRecorderを使って入れていき作成ボタンを押すと自動的にファイルを作成されるのでそっちを使ったほうがimportとか自動で楽なはず。

アプリを起動したスマホ(実機のほうが軽いし楽かも)を用意しておき

AndroidStudioのRunからRecordEspressoTest

image.png



操作していく

一部操作取れないボタンなどがあるかもしれませんが

TextInput周りは確実に取れたのでTextInputなどとりあえず1つでも要素を追加して

下記の様にトレースさせる。

取れるなら全部取ってしまう。





上記の様に取れたらTestを作成すると依存関係などすべて入ったテストファイルが生成される。

ので取れなかった要素を自力で入れる

今回では下記の様な関数を別途用意してみました。

    public void clickElement(String name) {

try {
ViewInteraction targetElement = onView(allOf(withContentDescription(name), isDisplayed()));
targetElement.perform((click()));
} catch(NoMatchingViewException ignore) {
Log.d("ClickElement", "Viewを見つけられませんでした。");
}
}

画面のロード待ちなど泥臭くsleep処理を入れて3秒待たせるなどにした。

本来はViewが表示されたらとかにしたほうが良いです。。。

    public void waitSleep(long millis) {

try{
Thread.sleep(millis);
} catch(InterruptedException e) {
System.out.println("sleepに失敗しました");
}
}

スクリーンショットに関しては

Firebase Test Lab インストゥルメンテーション テストのスクリーンショットを作成するの通りに依存関係を入れて

import com.google.android.libraries.cloudtesting.screenshots.ScreenShotter;

clickElement('LoginButton');
waitSleep(3000);
ScreenShotter.takeScreenshot(title, mActivityTestRule.getActivity());

でScreenShotが撮影できます。

実際のコードとしてはこんな感じ

image.png

sleepをクリックの前後に入れたりしているので

この程度ならjavaがわからない自分人にでも

testID系振ってclickElementで押してscreenshotで撮ってぐらいで

投げれるはず・・・???

ある程度テストを書いたら

作られたテストファイルを右クリックでRunしてローカルでテスト走らせたりしてみます。


Bitrise

TestFileが完成したら今度はBitriseに投げます。

やる事としてはReactNativeのBuildをBitriseに投げてある事前提ですが

1. AndroidBuildの部分をAndroid for Device Testingに変える

2. android-test.apkにsignする ← これに気づかず中々通らなかった

Androidのデバイステスト/Bitriseに書かれたとおりにやるだけです。

詰まった所とREADMEと違うところだけ上げていきます。


STEP1のメージのON/OFFスイッチはなくなっている?

image.png


Stepを増やす際の検索時に検索右のトグルをALLにしないとDeviceTesting系出ない

スクリーンショット 2019-09-04 0.26.52.png


Debug以外でのVariantでAssembleXXXXXXAndroidTestしたい

テストするビルドタイプの変更にある通り

android {

...
testBuildType "staging"
}

で設定できる。

ReactNativeの場合DebugBuildだとBundleしないとローカルでの開発サーバーがないと単体で動かず、app/build.gradleproject.ext.reactまわりのbundleInDebugをtrueなどに変えれば行けそうだったが

テストのdebugのときのみ変えるなど面倒だったのとほぼReleaseBuildのStagingBuildを用意していたのでStagingBuildでTestを走る様に上記を追加してBitriseのBuild for UITestingのVariantもStagingに変更する。

test.apkにもsignする

image.png

あとは

1. TestDeviceを決める Nexus4,22,ja,portraitとか

2. TestTypeを instrumentation

3. signしたtest.apkのpathを入れる

走らせれば動く(はず)です。

Buildページの上のTestReportsのViewから

image.png

Performanceや

image.png

VideoやScrennshotoが見れます。

image.png

ただScreenShotはなぜか表示されなくなったので別途TestArtifactsからDownloadしている・・・

調査中・・・コメント頂けると・・・


運用と言い訳

先週実装してみて

今週から深夜にTestBuildを走らせる

リリースもBitriseでAppStore/PlayStoreに投げるまでをBitriseで自動化していて

リリースビルドが叩かれたら終了後にテスト走らせるなど行っています。

これで最低限の画面の遷移と崩れとかには気づけるかなーという感じ

細かいロジックに関してはjestとかstorybookにまかせていって

NativeのUITestはあくまで全体のチェックに使う感じの運用になりそう。

ブランチプッシュしたらいつもStagingBuild走らせる様に普段はしてるのですが、

そこにまでテストを流すとインターン2人と自分が揃ったとき大渋滞しそうだなーっというのがあるのでデザイン系ブランチで気になったらBuildとかかなーとここは要調整。

またもしテストがだめになったとしてもtestIDの削除とjavaとobj-cのファイルの削除だけで住むので

万が一腐ったとしてもそこまでコード汚すことはないはず。

TestCodeに関しては数秒待つクリックの繰り返しでコード自体はClickとShotの繰り返しできれいだが秒で待たせたり雑な感じなのでちょいちょい改善していく予定・・・

JavaとJavaScript全然ちゃうやん・・・

きれいなJavaのテストコードの書き方とかあったらコメント下さい!お願いします!


最後に

AutoScaleではReactを使ったWeb/アプリの開発を行うエンジニアを募集しています!!

属人化せずに自動で動いて直せるし簡単に捨てられるみたいな状態を常に維持していきたいという心が強いので一緒に楽する方法を開発してみませんか!?

興味があればWantedlyからご応募やお話だけでもぜひ!!!

自社サービスのアプリ/WebサービスをReactで開発するメンバー募集!!

気合が溜まったらiOS編も書きます!