paint-brush
Como executar mais de 5.000 testes em dispositivos móveis todos os dias; Do manual do InDrive (parte 1)por@indrivetech
18,878 leituras
18,878 leituras

Como executar mais de 5.000 testes em dispositivos móveis todos os dias; Do manual do InDrive (parte 1)

por inDrive.Tech10m2023/05/30
Read on Terminal Reader

Muito longo; Para ler

O InDrive executa mais de 5.000 testes por dia em dispositivos iOS e Android combinados. O segredo é simples: usamos Selenoid. Para escrever testes do Appium, usamos: Kotlin; JUnit 5; Especialista. Achamos uma boa ideia dividir o material em duas partes: a primeira com foco no Android e a segunda no iOS.
featured image - Como executar mais de 5.000 testes em dispositivos móveis todos os dias; Do manual do InDrive (parte 1)
inDrive.Tech HackerNoon profile picture

Olá a todos! Meu nome é Taras Egorov; Sou engenheiro da inDrive. Vou mostrar como montamos uma infraestrutura capaz de rodar mais de 5.000 testes por dia em dispositivos iOS e Android combinados. O segredo é simples: usamos Selenoid.

Prefácio

No ano passado, nossos colegas conduziram um estudo sobre testes automáticos e nós participamos de uma pesquisa como parte do estudo.

Dos entrevistados, o Appium foi usado por cerca de 20% das equipes, o que não é um mau começo.


Ficamos satisfeitos com os resultados da pesquisa, então decidimos escrever um artigo para compartilhar nossa experiência com você e obter alguns conselhos em troca. Achamos uma boa ideia dividir o material em duas partes: a primeira com foco no Android e a segunda no iOS.


Vamos começar com o Android.

Executando os testes no Android

Selenoid é uma ferramenta popular para executar e gerenciar navegadores e emuladores Android em um contêiner Docker. Você pode ler mais sobre isso na documentação .


Para escrever testes do Appium, usamos:

  • Kotlin;
  • JUnit 5;
  • Especialista.

A primeira corrida. Configurando o Selenóide

  1. Crie um arquivo de configuração browsers.json :


 {  "android": {    "default": "10.0",    "versions": {      "10.0": {        "image": "browsers/android:10.0",        "port": "4444",        "path": "/wd/hub"      }    }  } }


A imagem do emulador é especificada em image . Os caras do aerokube prepararam imagens prontas de emuladores Android. Você pode conferir aqui ou aqui . As imagens não diferem umas das outras de forma alguma.


Vamos usar a imagem browsers/android:10.0 como exemplo. A imagem deve ser baixada previamente: docker pull browsers/android:10.0 , caso contrário os testes não serão executados:


 Original error: create container: Error response from daemon: No such image: browsers/android:10.0


  1. O próximo passo é executar o Selenoid. Fazemos isso diretamente via docker , ou existe a opção de usar o 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


Você pode verificar se o Selenoid está funcionando corretamente seguindo o link http://localhost:4444 em seu navegador:


 You are using Selenoid 1.10.7!


  1. Especifique o endereço Selenoid nos testes Appium no driver:


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


  1. Em seguida, especifique o link para os recursos integrados:


 ... capabilities.setCapability("appium:app", "https://storage.example.com/builds/app.apk") ...


Se não for possível fornecer um link, você pode especificar o caminho para a compilação:**


 ... capabilities.setCapability("appium:app", "/builds/app.apk") ...


Onde /builds/app.apk é o caminho dentro do contêiner onde o emulador está sendo executado. Para que esta opção funcione corretamente, certifique-se de especificar os volumes em browsers.json :


 {  "android": {    "default": "10.0",    "versions": {      "10.0": {        ...        "volumes": [          "/home/username/app.apk:/builds/app.apk:ro"        ]        ...      }    }  } }


Em que /home/username/app.apk é o caminho para a compilação na plataforma host.


É isso, quase configuramos o Selenoid, e agora podemos tentar rodar os testes:


 ./mvnw test


Mas, infelizmente, os testes não poderão ser executados. Vamos investigar isso e ver o que há de errado.

A segunda corrida. Dando uma olhada nos logs e no vídeo

A primeira coisa a fazer após uma falha na inicialização é verificar os logs do 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]


Vemos que o status é SERVICE_STARTUP_FAILED. Vá para a documentação e veja o valor do status:


 SERVICE_STARTUP_FAILED - Failed to start Docker container or driver binary


O erro não informa muito e mais informações são necessárias. Seria bom dar uma olhada nos logs do container. Vamos fazer isso ativando o log:


 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


Também habilitamos logs na seção Capabilities:


 ... capabilities.setCapability("enableLog", true) ...


Execute os testes e revise os logs usando o navegador 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.


Os logs do contêiner também não ajudam muito aqui, porque você não pode ver os logs do Appium. Agora vamos tentar ativá-los. Para fazer isso, vamos ver a entrada do script point.sh :


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


Para ativar os logs do Appium, os parâmetros VERBOSE=true e APPIUM_ARGS=--log-level debug : devem ser passados para o container:


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


Para permitir que o Appium depure logs, você precisa passar VERBOSE; neste caso, os logs do emulador ligam e começam a preencher o "ether"” Mas corrigimos isso para imagens futuras =)


Agora basta passar para 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 ...


Como visto nos logs, o Appium não consegue encontrar nosso elemento. Vamos ver o que está acontecendo na tela do emulador. Para fazer isso, temos que executar a IU do Selenoid:


 docker run -d \           --name selenoid-ui \           -p 8080:8080 \           --link selenoid:selenoid \           aerokube/selenoid-ui:1.10.4 \           --selenoid-uri "http://selenoid:4444"


Acesse http://0.0.0.0:8080 e abra a IU do Selenoid:


É assim que a IU do Selenoid se parece


Certifique-se de ativar o VNC e a gravação de vídeo nos testes:


 ... capabilities.setCapability("enableVNC", true) capabilities.setCapability("enableVideo", true) ...


O comando de inicialização do Selenoid fica assim:


 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


Abra a IU do Selenoid assim que os testes estiverem em execução:


É assim que o processo de inicialização na IU do Selenoid se parece


VNC e registros


E aqui está um vídeo dele .


Encontramos a causa do erro de inicialização. Ótimo! Vamos continuar.

A terceira corrida. Como criar uma imagem do emulador

Acontece que as imagens dos emuladores Selenoid não funcionam sem os serviços do Google Play. Para remediar essa situação, você mesmo deve criar uma imagem do emulador. Os caras do aerokube reuniram tudo o que você precisa para isso: um repositório com fotos e documentação .


  1. Baixando o repositório.
  2. Vá para a pasta selenium .
  3. Execute o script ./automate_android.sh e responda às perguntas. É assim que fica no nosso caso:


 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


Quando vi a pergunta Adicionar instantâneo de inicialização rápida do Android?, pensei que fosse um instantâneo do emulador . Mas se você olhar o código , ele chama um script , que é necessário para instalar aplicativos APK. Basicamente, não nos dá nenhum ganho.


Já usamos emuladores de snapshot para acelerar lançamentos de contêineres , mas falaremos sobre isso em outros artigos.


  1. Depois que a imagem for criada, seremos solicitados a enviá-la para o registro. Como ainda não precisamos disso, gentilmente recusaremos a oferta:


 Push? >> n


Montamos uma compilação com os serviços do Google Play. Lembre-se de alterar o parâmetro de imagem em browsers.json e reinicie o Selenoid.


Agora vamos tentar refazer os testes:


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


E aqui está um vídeo do teste.


Resumindo

O que fizemos:


  • Selenoid configurado para executar testes Android.
  • Aprendeu como verificar os logs e vídeos para solucionar problemas.
  • Construímos nossa própria imagem de emulador com os serviços do Google Play.


Outra coisa que gostaria de contar a vocês:


  • Tempo limite do selenóide. Se seu aplicativo for grande, você pode ter problemas com tempos limite.
  • Como tentamos fazer o contêiner rodar mais rápido. O vídeo mostra que a corrida leva cerca de um minuto ou mais.
  • Como tentamos executar testes nativos do Android escritos em Espresso no Selenoid. Alerta de spoiler: isso funciona!


Enquanto isso, na próxima parte, contaremos como escalamos a infraestrutura e fizemos testes no iOS.