こんにちは、みんな!私の名前はタラス・エゴロフです。私はinDriveのエンジニアです。 iOS デバイスと Android デバイスを合わせて 1 日あたり 5,000 件を超えるテストを実行できるインフラストラクチャをどのようにセットアップしたかを説明します。秘密は単純です。Selenoid を使用したからです。
昨年、私たちの同僚は自動テストの研究を実施し、私たちはその研究の一環としてアンケートに参加しました。
私たちは調査結果に満足していたので、私たちの経験を皆さんと共有し、アドバイスを得るために記事を書くことにしました。私たちは、資料を 2 つのパートに分割するのが良いと考えました。1 つ目は Android に焦点を当て、2 つ目は iOS に焦点を当てました。
まずは Android から始めましょう。
Selenoid は、Docker コンテナーでブラウザーや Android エミュレーターを実行および管理するための一般的なツールです。詳細については、ドキュメントを参照してください。
Appium テストを作成するには、以下を使用します。
browsers.json
構成ファイルを作成します。
{ "android": { "default": "10.0", "versions": { "10.0": { "image": "browsers/android:10.0", "port": "4444", "path": "/wd/hub" } } } }
エミュレータイメージはimage
で指定されます。 aerokubeの人たちは、Android エミュレータの既製のイメージを用意しました。ここまたはここ で確認できます。画像は互いに何の違いもありません。
例として、画像browsers/android:10.0
を見てみましょう。イメージは事前にダウンロードする必要があります: docker pull browsers/android:10.0
。そうしないとテストは実行されません。
Original error: create container: Error response from daemon: No such image: browsers/android:10.0
docker run -d \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "$(pwd)/selenoid/config/":/etc/selenoid/:ro \ -p 4444:4444 \ --name selenoid \ aerokube/selenoid:1.10.7
ブラウザでhttp://localhost:4444のリンクをクリックすると、Selenoid が適切に動作しているかどうかを確認できます。
You are using Selenoid 1.10.7!
ドライバーの Appium テストで Selenoid アドレスを指定します。
... val driver = AndroidDriver(URL("http://localhost:4444/wd/hub"), capabilities) ...
... capabilities.setCapability("appium:app", "https://storage.example.com/builds/app.apk") ...
リンクを提供できない場合は、ビルドへのパスを指定できます:**
... capabilities.setCapability("appium:app", "/builds/app.apk") ...
/builds/app.apk
は、エミュレータが実行されているコンテナ内のパスです。このオプションが適切に機能するには、 browsers.json
でvolumes
必ず指定してください。
{ "android": { "default": "10.0", "versions": { "10.0": { ... "volumes": [ "/home/username/app.apk:/builds/app.apk:ro" ] ... } } } }
/home/username/app.apk
ホスト プラットフォーム上のビルドへのパスです。
これで Selenoid のセットアップがほぼ完了したので、テストを実行してみましょう。
./mvnw test
ただし、残念ながらテストは実行できません。これを調べて、何が問題なのか見てみましょう。
起動に失敗した後に最初に行うことは、Selenoid ログを確認することです。
docker logs selenoid
[INIT] [Loading configuration files...] [INIT] [Loaded configuration from /etc/selenoid/browsers.json] [INIT] [Video Dir: /opt/selenoid/video] [INIT] [Your Docker API version is 1.41] [INIT] [Timezone: UTC] [INIT] [Listening on :4444] [NEW_REQUEST] [unknown] [172.17.0.1] [NEW_REQUEST_ACCEPTED] [unknown] [172.17.0.1] [LOCATING_SERVICE] [android] [10.0] [USING_DOCKER] [android] [10.0] [CREATING_CONTAINER] [selenoid/android:10.0] [STARTING_CONTAINER] [selenoid/android:10.0] [75e454341da7fc4b58ba104a5180813bac6cd7c124037a759b6c976e65b168fa] [CONTAINER_STARTED] [selenoid/android:10.0] [75e454341da7fc4b58ba104a5180813bac6cd7c124037a759b6c976e65b168fa] [0.40s] [0] [REMOVING_CONTAINER] [75e454341da7fc4b58ba104a5180813bac6cd7c124037a759b6c976e65b168fa] [0] [CONTAINER_REMOVED] [75e454341da7fc4b58ba104a5180813bac6cd7c124037a759b6c976e65b168fa] [0] [SERVICE_STARTUP_FAILED] [http://172.17.0.3:4444/wd/hub does not respond in 30s]
ステータスが SERVICE_STARTUP_FAILED であることがわかります。ドキュメントにアクセスしてステータス値を確認してください。
SERVICE_STARTUP_FAILED - Failed to start Docker container or driver binary
このエラーからは多くのことはわかりません。さらに詳しい情報が必要です。コンテナのログを確認してみると良いでしょう。ロギングを有効にしてこれを実行しましょう。
docker run -d \ -p 4444:4444 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "$(pwd)/selenoid/config/":/etc/selenoid/:ro \ -v "$(pwd)/selenoid/logs/":/opt/selenoid/logs/ \ aerokube/selenoid:1.10.7 \ -log-output-dir /opt/selenoid/logs
また、「機能」セクションでログを有効にします。
... capabilities.setCapability("enableLog", true) ...
テストを実行し、ブラウザhttp://localhost:4444/logs/を使用してログを確認します。
2023-04-16T13:44:43.909768530Z Waiting X server... 2023-04-16T13:44:44.009494775Z Logging to: /tmp/fluxbox.log 2023-04-16T13:44:44.047587277Z Waiting X server... 2023-04-16T13:44:44.151933325Z Waiting X server... 2023-04-16T13:44:44.262850410Z * daemon not running; starting now at tcp:5037 2023-04-16T13:44:44.457972956Z * daemon started successfully 2023-04-16T13:44:44.458249266Z adb: no devices/emulators found 2023-04-16T13:44:45.463480812Z adb: no devices/emulators found 2023-04-16T13:44:46.471547723Z adb: no devices/emulators found 2023-04-16T13:44:47.476093515Z adb: no devices/emulators found 2023-04-16T13:44:48.481987351Z adb: no devices/emulators found 2023-04-16T13:44:49.486503149Z adb: no devices/emulators found 2023-04-16T13:44:50.492757801Z adb: no devices/emulators found 2023-04-16T13:44:51.499094108Z adb: no devices/emulators found 2023-04-16T13:44:52.505862428Z adb: no devices/emulators found 2023-04-16T13:44:53.513276412Z adb: no devices/emulators found 2023-04-16T13:44:54.520642210Z adb: no devices/emulators found 2023-04-16T13:44:55.527420189Z adb: no devices/emulators found 2023-04-16T13:44:56.534631013Z adb: no devices/emulators found 2023-04-16T13:44:57.316094939Z WARNING. Using fallback path for the emulator registration directory. 2023-04-16T13:44:57.335415397Z checkValid: hw configs not eq 2023-04-16T13:44:57.541959741Z adb: device offline 2023-04-16T13:44:58.547907700Z adb: device offline 2023-04-16T13:44:58.565504866Z emulator: WARNING: System image is writable 2023-04-16T13:44:58.565528396Z emulator: Cold boot: different AVD configuration 2023-04-16T13:44:58.565532576Z Your emulator is out of date, please update by launching Android Studio: 2023-04-16T13:44:58.565536346Z - Start Android Studio 2023-04-16T13:44:58.565539506Z - Select menu "Tools > Android > SDK Manager" 2023-04-16T13:44:58.565543076Z - Click "SDK Tools" tab 2023-04-16T13:44:58.565546216Z - Check "Android Emulator" checkbox 2023-04-16T13:44:58.565549216Z - Click "OK" 2023-04-16T13:44:58.565552146Z 2023-04-16T13:44:59.554451514Z adb: device offline 2023-04-16T13:45:00.560926060Z adb: device offline 2023-04-16T13:45:01.568777440Z adb: device offline 2023-04-16T13:45:12.124226047Z emulator: INFO: boot completed 2023-04-16T13:45:12.124251007Z emulator: INFO: boot time 27848 ms 2023-04-16T13:45:12.124255077Z emulator: Increasing screen off timeout, logcat buffer size to 2M. 2023-04-16T13:45:12.152557294Z emulator: Revoking microphone permissions for Google App.
Appium ログは表示されないため、ここでもコンテナ ログはあまり役に立ちません。それでは、それらを有効にしてみましょう。これを行うには、スクリプトのエントリ point.shを見てみましょう。
... if [ -z "$VERBOSE" ]; then APPIUM_ARGS="$APPIUM_ARGS --log-level error" else EMULATOR_ARGS="$EMULATOR_ARGS -verbose" fi ...
Appium ログを有効にするには、パラメータVERBOSE=true
およびAPPIUM_ARGS=--log-level debug
: をコンテナに渡す必要があります。
{ "android": { "default": "10.0", "versions": { "10.0": { ... "env": [ "VERBOSE=true", "APPIUM_ARGS=--log-level debug" ] ... } } } }
Appium でログをデバッグできるようにするには、VERBOSE を渡す必要があります。この場合、エミュレータのログがオンになり、「エーテル」の充填が開始されます。」 しかし、将来のイメージのためにそれを修正しました =)
これで、 APPIUM_ARGS=-log-level debug
に渡すだけで十分です。
... [HTTP] --> POST /wd/hub/session/c89fa9c2-ca2b-49cd-ab31-590eeccf77d1/element [HTTP] {"using":"id","value":"authorization_edittext_phone"} [debug] [W3C (c89fa9c2)] Calling AppiumDriver.findElement() with args: ["id","authorization_edittext_phone"," c89fa9c2-ca2b-49cd-ab31-590eeccf77d1"] [debug] [BaseDriver] Valid locator strategies for this request: xpath, id, class name, accessibility id, -and roid uiautomator [debug] [BaseDriver] Waiting up to 0 ms for condition [debug] [WD Proxy] Matched '/element' to command name 'findElement' [debug] [WD Proxy] Proxying [POST /element] to [POST http://127.0.0.1:8200/wd/hub/session/65943f03-3b35-4d3eb221-d6dc7988f935/element] with body: {"strategy":"id","selector": "authorization_edittext_phone","context":"","multiple":false} [WD Proxy] Got response with status 404: {"sessionId":"65943f03-3b35-4d3e-b221-d6dc7988f935","value":{"error" :"no such element","message":"An element could not be located on the page using the given search parameters","stacktrace":"io.appium.uiautomator2.common.exceptions.El ementNotFoundException: An element could not be located on the page using the given search parameters\n\tat io.appium.uiautomator2.handler.FindElement.safeHandle(Find Element.java:73)\n\tat io.appium.uiautomator2.handler.request.SafeRequestHandler.handle(SafeRequestHandler.java:41)\n\tat io.appium.uiautomator2.server.AppiumServlet. handleRequest(AppiumServlet.java:253)\n\tat io.appium.uiautomator2.server.AppiumServlet.handleHttpRequest(AppiumServlet.java:247)\n\tat io.appium.uiautomator2.http.Se rverHandler.channelRead(ServerHandler.java:68)\n\tat io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:366)\n\tat io .netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:352)\n\tat io.netty.chann... [debug] [W3C] Matched W3C error code 'no such element' to NoSuchElementError [debug] [W3C (c89fa9c2)] Encountered internal error running command: NoSuchElementError: An element could not be located on the page using the given search parameters. [debug] [W3C (c89fa9c2)] at AndroidUiautomator2Driver.findElOrEls (/opt/node_modules/appium/node_modules/appium-android-driver/lib/commands/find.js:75:11) [debug] [W3C (c89fa9c2)] at process._tickCallback (internal/process/next_tick.js:68:7) [HTTP] <-- POST /wd/hub/session/c89fa9c2-ca2b-49cd-ab31-590eeccf77d1/element 404 23 ms - 444 ...
ログからわかるように、Appium は要素を見つけることができません。エミュレータ画面で何が起こっているのか見てみましょう。これを行うには、Selenoid UI を実行する必要があります。
docker run -d \ --name selenoid-ui \ -p 8080:8080 \ --link selenoid:selenoid \ aerokube/selenoid-ui:1.10.4 \ --selenoid-uri "http://selenoid:4444"
http://0.0.0.0:8080に移動し、Selenoid UI を開きます。
テストでは必ず VNC とビデオ録画を有効にしてください。
... capabilities.setCapability("enableVNC", true) capabilities.setCapability("enableVideo", true) ...
Selenoid 起動コマンドは次のようになります。
docker run -d \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "(pwd)/selenoid/logs/":/opt/selenoid/logs/ \ -v /opt/selenoid/video/:/opt/selenoid/video/ \ -e OVERRIDE_VIDEO_OUTPUT_DIR="/opt/selenoid/video/" \ -p 4444:4444 \ -name selenoid \ aerokube/selenoid:1.10.7 \ -log-output-dir /opt/selenoid/logs
テストが起動して実行されたら、Selenoid UI を開きます。
そして、これがそのビデオです。
起動エラーの原因が判明しました。素晴らしい!次へ移りましょう。
結局のところ、Selenoid エミュレータのイメージは Google Play サービスなしでは動作しません。この状況を解決するには、エミュレータ イメージを自分で構築する必要があります。 aerokube のスタッフは、写真とドキュメントを含むリポジトリなど、これに必要なものをすべてまとめてくれました。
selenium
フォルダーに移動します。./automate_android.sh
を実行し、質問に答えます。私たちの場合は次のようになります。
Specify Appium version: [1.18.1] >> 1.18.1 Specify Android image type (possible values: "default", "google_apis", "google_apis_playstore", "android-tv", "android-wear"): [default] >> google_apis Specify Application Binary Interface (possible values: "armeabi-v7a", "arm64-v8a", "x86", "x86_64"): [x86] >> x86 Specify Android version: [8.1] >> 10.0 Specify device preset name if needed (eg "Nexus 4"): >> Specify SD card size, Mb: [500] >> Specify userdata.img size, Mb: [500] >> Are you building a Chrome Mobile image (for mobile web testing): [n] >> y Specify Chromedriver version if needed (required for Chrome Mobile): >> 74.0.3729.6 Specify image tag: [selenoid/chrome-mobile:74.0] >> android-emulator:10.0 Add Android quick boot snapshot? [y] >> n
「Android クイック ブート スナップショットを追加しますか?」という質問を見たとき、これはエミュレータスナップショットだと思いました。しかし、コードを見ると、APK アプリケーションをインストールするために必要なスクリプトを呼び出しています。基本的に、それは私たちに何の利益も与えません。
コンテナの起動を高速化するためにすでにスナップショット エミュレータを使用していますが、それについては他の記事で説明します。
イメージが構築されると、それをレジストリにプッシュするように求められます。まだ必要ではないため、この申し出はお断りさせていただきます。
Push? >> n
Google Play サービスを使用してビルドをまとめました。忘れずに、browsers.json の image パラメータを変更し、Selenoid を再起動してください。
次に、テストを再実行してみましょう。
[INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------
そして、こちらが試運転の動画です。
私たちが行ったこと:
他にお伝えしたいこと:
一方、次のパートでは、インフラストラクチャをスケールアップし、iOS でテストを実行した方法について説明します。