BitriseでReactNativeのUITestを走らせてみた話
AutoScale,Inc.でアプリの運用から開発をやっている@t0m0120です!
前回のレビュー施策に引き続き今回はReactNativeTokyo#6で登壇させていただいた際のスライドReactNativeアプリをBitrise上でUITestしてみた話の詳細記事という感じです。
長すぎたので一旦Androdのみにしました
WF-1000XM3ノイキャンやばすぎて集中力30%ぐらいバフされてる気がします。
そもそもなぜUITest走らせたくなったのか
-
iPhone/Android端末多すぎ問題
デザインの修正などいちいち確認するのが面倒だけど崩れとか最低限よく使われる端末は安定させたい。 -
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を候補にあげた。が
無料枠だと1日5件か10件
デバイスだと1時間1~5$と毎日走らせたりビルドのたびに走らせてチェックするにはちょっとお金かかりそうかなーと思っていたところに
普段使っているBitrise上に
DeviceTestingAndroid
と
DeviceTestingIOS
を発見
Bitriseを使っていれば特に金額もかからずBitrise経由でTestlab叩いているっぽい。
対応端末も
Android
iOS
と見た感じ一番小さい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分)
テストコードを書く
ReactNative
<LoginButton
testID='LoginButton'
accessible,
accessibilityLabel='LoginButton'
>
// 実際は
<LoginButton
{...set_id('LoginButton')}
>
// でReleaseBuildはnull開発系でiOSはtestID/Androidはaccessibilityみたいにしてる。
上のように遷移するボタンに一通りtestID
とaccessible, Label
を追加しておく。
Android
一番メジャーそうかつTestLabで押されているEspressoを採用しました。
Espresso setup instructionsの通りにTest周りの依存関係を入れてからテストファイルは作成せずに
EspressoTestRecorderのとおりにAndroidStudioからアプリを立ち上げた状態でTestRecorderを使って入れていき作成ボタンを押すと自動的にファイルを作成されるのでそっちを使ったほうがimportとか自動で楽なはず。
アプリを起動したスマホ(実機のほうが軽いし楽かも)を用意しておき
AndroidStudioのRunからRecordEspressoTest
↓
操作していく
一部操作取れないボタンなどがあるかもしれませんが
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が撮影できます。
実際のコードとしてはこんな感じ
sleepをクリックの前後に入れたりしているので
この程度ならjavaがわからない自分人にでも
testID系振ってclickElementで押してscreenshotで撮ってぐらいで
投げれるはず・・・???
ある程度テストを書いたら
作られたテストファイルを右クリックでRunしてローカルでテスト走らせたりしてみます。
Bitrise
TestFileが完成したら今度はBitriseに投げます。
やる事としてはReactNativeのBuildをBitriseに投げてある事前提ですが
-
AndroidBuild
の部分をAndroid for Device Testing
に変える -
android-test.apk
にsignする ← これに気づかず中々通らなかった
Androidのデバイステスト/Bitriseに書かれたとおりにやるだけです。
詰まった所とREADMEと違うところだけ上げていきます。
STEP1のメージのON/OFFスイッチはなくなっている?
Stepを増やす際の検索時に検索右のトグルをALLにしないとDeviceTesting系出ない
Debug以外でのVariantでAssembleXXXXXXAndroidTestしたい
テストするビルドタイプの変更にある通り
android {
...
testBuildType "staging"
}
で設定できる。
ReactNativeの場合DebugBuildだとBundleしないとローカルでの開発サーバーがないと単体で動かず、app/build.gradle
のproject.ext.react
まわりのbundleInDebugをtrueなどに変えれば行けそうだったが
テストのdebugのときのみ変えるなど面倒だったのとほぼReleaseBuildのStagingBuildを用意していたのでStagingBuildでTestを走る様に上記を追加してBitriseのBuild for UITestingのVariantもStagingに変更する。
test.apkにもsignする
あとは
- TestDeviceを決める
Nexus4,22,ja,portrait
とか - TestTypeを
instrumentation
へ - signしたtest.apkのpathを入れる
走らせれば動く(はず)です。
Buildページの上のTestReportsのViewから
Performanceや
VideoやScrennshotoが見れます。
ただ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編も書きます!