paint-brush
매일 모바일 장치에서 5000개 이상의 테스트를 실행하는 방법 inDrive의 플레이북(1부)에서~에 의해@indrivetech
18,917 판독값
18,917 판독값

매일 모바일 장치에서 5000개 이상의 테스트를 실행하는 방법 inDrive의 플레이북(1부)에서

~에 의해 inDrive.Tech10m2023/05/30
Read on Terminal Reader
Read this story w/o Javascript

너무 오래; 읽다

InDrive는 iOS 및 Android 장치를 합해 매일 5,000개 이상의 테스트를 실행합니다. 비결은 간단합니다. 우리는 Selenoid를 사용했습니다. Appium 테스트를 작성하려면 다음을 사용합니다. Kotlin; JUnit 5; 메이븐. 우리는 자료를 두 부분으로 나누는 것이 좋은 생각이라고 생각했습니다. 첫 번째 부분은 Android에 초점을 맞추고 두 번째 부분은 iOS에 중점을 두었습니다.
featured image - 매일 모바일 장치에서 5000개 이상의 테스트를 실행하는 방법 inDrive의 플레이북(1부)에서
inDrive.Tech HackerNoon profile picture

안녕하세요 여러분! 내 이름은 Taras Egorov입니다. 저는 inDrive의 엔지니어입니다. iOS 및 Android 기기를 합쳐서 하루에 5,000개 이상의 테스트를 실행할 수 있는 인프라를 어떻게 설정했는지 보여드리겠습니다. 비결은 간단합니다. 우리는 Selenoid를 사용했습니다.

머리말

작년에 우리 동료들은 자동 테스트에 관한 연구를 진행했고, 우리도 연구의 일환으로 설문조사에 참여했습니다.

설문조사에 참여한 팀 중 약 20%가 Appium을 사용했는데, 이는 나쁜 출발이 아닙니다.


우리는 설문 조사 결과에 만족하여 우리의 경험을 여러분과 공유하고 이에 대한 조언을 얻기 위해 기사를 작성하기로 결정했습니다. 우리는 자료를 두 부분으로 나누는 것이 좋은 생각이라고 생각했습니다. 첫 번째 부분은 Android에 초점을 맞추고 두 번째 부분은 iOS에 중점을 두었습니다.


안드로이드부터 시작해 보겠습니다.

Android에서 테스트 실행

Selenoid는 Docker 컨테이너에서 브라우저와 Android 에뮬레이터를 실행하고 관리하는 데 널리 사용되는 도구입니다. 이에 대한 자세한 내용은 설명서를 참조하세요.


Appium 테스트를 작성하려면 다음을 사용합니다.

  • 코틀린;
  • JUnit 5;
  • 메이븐.

첫 번째 실행. 셀레노이드 설정

  1. 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


  1. 다음 단계는 Selenoid를 실행하는 것입니다. docker 를 통해 직접 수행하거나 Configuration Manager 를 사용하는 옵션이 있습니다.


 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!


  1. 드라이버의 Appium 테스트에서 Selenoid 주소를 지정합니다.


 ... val driver = AndroidDriver(URL("http://localhost:4444/wd/hub"), capabilities) ...


  1. 다음으로 내장 기능에 대한 링크를 지정합니다.


 ... 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 로그를 볼 수 없기 때문에 컨테이너 로그는 여기서도 별로 도움이 되지 않습니다. 이제 이를 활성화해 보겠습니다. 이를 위해 스크립트 진입점.sh를 살펴보겠습니다.


 ... if [ -z "$VERBOSE" ]; then APPIUM_ARGS="$APPIUM_ARGS --log-level error" else EMULATOR_ARGS="$EMULATOR_ARGS -verbose" fi ...


Appium 로그를 활성화하려면 VERBOSE=trueAPPIUM_ARGS=--log-level debug 매개변수를 컨테이너에 전달해야 합니다.


 {  "android": {    "default": "10.0",    "versions": {      "10.0": {        ...        "env": [          "VERBOSE=true",          "APPIUM_ARGS=--log-level debug"        ]        ...      }    }  } }


Appium에서 로그를 디버깅할 수 있도록 하려면 VERBOSE를 전달해야 합니다. 이 경우 에뮬레이터 로그가 켜지고 "ether"를 채우기 시작합니다.” 그러나 향후 이미지를 위해 이를 수정했습니다 =)


이제 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를 엽니다.


셀레노이드 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 UI의 시작 프로세스는 다음과 같습니다.


VNC 및 로그


여기에 대한 비디오가 있습니다.

시작 오류의 원인을 찾았습니다. 엄청난! 계속 진행합시다.

세 번째 실행. 에뮬레이터 이미지 빌드

결과적으로 Selenoid 에뮬레이터의 이미지는 Google Play 서비스 없이는 작동하지 않습니다. 이 상황을 해결하려면 에뮬레이터 이미지를 직접 빌드해야 합니다. aerokube의 사람들은 이를 위해 필요한 모든 것을 모았습니다: 사진과 문서가 있는 저장소 .


  1. 저장소를 다운로드하는 중입니다 .
  2. selenium 폴더로 이동합니다.
  3. ./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 애플리케이션을 설치하는 데 필요한 스크립트를 호출합니다. 기본적으로 그것은 우리에게 어떤 이득도 주지 않습니다.


우리는 컨테이너 실행 속도를 높이기 위해 이미 스냅샷 에뮬레이터를 사용하고 있지만 이에 대해서는 다른 기사에서 다루겠습니다.


  1. 이미지가 빌드되면 이를 레지스트리에 푸시하라는 메시지가 표시됩니다. 아직은 필요하지 않으므로 해당 제안을 정중히 거절하겠습니다.


 Push? >> n


Google Play 서비스로 빌드를 구성했습니다. browsers.json에서 이미지 매개변수를 변경하고 Selenoid를 다시 시작하는 것을 잊지 마세요.


이제 테스트를 다시 실행해 보겠습니다.


 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------


그리고 아래는 테스트 실행 영상입니다 .

요약하자면

우리가 한 일:


  • Android 테스트를 실행하도록 Selenoid를 구성했습니다.
  • 문제 해결을 위해 로그와 비디오를 확인하는 방법을 배웠습니다.
  • Google Play 서비스를 사용하여 자체 에뮬레이터 이미지를 구축했습니다.


그 밖에 제가 말씀드리고 싶은 내용은 다음과 같습니다.


  • 셀레노이드 시간 초과. 앱이 큰 경우 시간 초과 문제가 발생할 수 있습니다.
  • 컨테이너를 더 빠르게 실행하려고 시도한 방법입니다. 동영상을 보면 실행에 약 1분 정도 소요되는 것으로 나와 있습니다.
  • Selenoid에서 Espresso로 작성된 기본 Android 테스트를 실행해 본 방법. 스포일러 경고: 작동합니다!


한편, 다음 부분에서는 인프라를 확장하고 iOS에서 테스트를 실행한 방법을 알려 드리겠습니다.