}

How to use Appium for automated app testing

Testen speelt een cruciale rol tijdens de ontwikkeling van een app en kan, mits goed uitgevoerd, enorm veel tijd besparen. Het handmatig herhalen van tests is duur en tijdrovend; daarom zijn er testautomatisering frameworks in het leven geroepen. Appium is een van de populairste frameworks voor testautomatisering in de mobiele wereld. Het is een opensourceframework voor native, hybride en mobiele web-apps en is zeer goed gedocumenteerd. Appium is een krachtig framework waarmee je tests onafhankelijk van je app kunt schrijven. Tests kunnen worden geschreven in Java, Objective-C, JavaScript (Node), PHP, Python, Ruby, C#, Clojure of Perl met behulp van de Selenium WebDriver API en taalspecifieke client-libraries.

Hoe gebruik je Appium?

Appium wordt geleverd met drie tools:

Appium server

De Appium server is een HTTP REST-API die verantwoordelijk is voor het detecteren van en communiceren met testapparaten. Appium ondersteunt zowel emulators als fysieke apparaten. Tegenwoordig is Appium geïntegreerd in GitLab CI, AWS, Bitrise en andere cloudapplicaties. Indien nodig kun je de API ook gebruiken om volledig je eigen integratie te schrijven.

Appium desktop

Desktop is een app voor Mac, Windows en Linux die de kracht van de Appium automatiseringsserver verpakt in een mooie en flexibele UI.

Appium Inspector

Appium inspector is een tool waarmee je elementen van een mobiele app kunt inspecteren. Bij het schrijven van mobiele tests moet je UI-elementen identificeren aan de hand van bepaalde ID's. Met Appium inspector kun je die ID's vinden zonder dat je de broncode nodig hebt.

Zodra de Appium server draait, kun je communiceren met de API via een van de eerder genoemde programmeertalen of via Appium inspector.

Appium Desired Capabilities: Wat zijn dat?

Voordat je begint met testen, moet je begrijpen wat de Desired Capabilities van Appium zijn. Dit is in wezen een JSON-document dat door de Appium-client naar de server wordt gestuurd zodra er een nieuwe automatiseringssessie wordt aangevraagd. Dit document bevat cruciale gegevens over hoe je sessie moet verlopen. Denk hierbij aan het apparaat dat je wilt gebruiken, welke app er gestart moet worden, of de app vooraf verwijderd moet worden en welke browser je wilt testen. Appium ondersteunt vrijwel alle emulators, fysieke apparaten en browsers.

Configureren voor Android en iOS

Voor een Android-emulator (zoals een gesimuleerde Samsung Galaxy A40) specificeer je de platformgegevens, de apparaatnaam en de UDID. Daarnaast vereist Android een pad naar je APK-bestand via de eigenschap "app", óf twee specifieke eigenschappen die het app-pakket en de opstartactiviteit van de app definiëren (zoals gedefinieerd in je AndroidManifest.xml).

Bij iOS moeten fysieke apparaten eerst worden geprovisioned. In de JSON-configuratie gebruik je hier specifieke eigenschappen voor, zoals xcodeOrgId en xcodeSigningId. In plaats van de bundleId kun je hier ook de eigenschap "app" gebruiken om rechtstreeks naar een IPA-bestand te verwijzen. Een typische configuratie ziet er als volgt uit:

JSON

{
 "appium:platformName": "Android",
 "appium:platformVersion": "11",
 "appium:deviceName": "Samsung Galaxy A40",
 "appium:udid": "******",
 "appium:appPackage": "com.coffeeit.appium_example",
 "appium:appActivity": "com.coffeeit.appium_example.MainActivity",
 "appium:noReset": "false",
 "appium:fullReset": "false"
}

Wat doen "noReset" and "fullReset"?

Beginnende Appium-gebruikers raken vaak in de war door de keys "noReset" en "fullReset". Deze eigenschappen instrueren Appium om de app-gegevens te wissen of de app volledig te verwijderen voordat een test start. Dit is bijvoorbeeld ontzettend handig wanneer je de onboarding-flow van een app herhaaldelijk vanaf een schone lei wilt testen.

  • Als noReset op true staat, worden alle app-gegevens gewist.
  • Als fullReset op true staat, wordt de app verwijderd en opnieuw geïnstalleerd (dit is alleen mogelijk als er een pad naar een APK/IPA is opgegeven).

Persoonlijk wis ik altijd de app-gegevens, omdat je niet blind kunt vertrouwen op de status van een app. Het wissen van de app-gegevens geeft een test een hogere slaagkans.

Accessibility ID's

Bij het schrijven van tests moeten we communiceren met UI-elementen. Er zijn verschillende manieren om dit te doen. UI-elementen zijn herkenbaar aan:

  • ID
  • Accessibility ID
  • XPath: Het geneste pad van een element
  • Class name: De klassenaam van het element
  • Tag name
  • En diverse andere Android/iOS-gerelateerde methoden

De beste manier is om accessibility ID's te gebruiken. Simpelweg omdat accessibility ID's geen codewijzigingen vereisen en gesynchroniseerd kunnen worden tussen meerdere apps. Dus als je een Android- en een iOS-app hebt, kun je (afhankelijk van hoeveel ze van elkaar verschillen) dezelfde test voor beide apps gebruiken. Dit betekent dat je geen aparte test hoeft te maken voor Android en een andere voor iOS. Bovendien kun je if-statements in je code gebruiken om UI-bewerkingen uit te voeren die alleen voor iOS of alleen voor Android gelden.

Tests schrijven met Kotlin

Nu we begrijpen wat de Desired Capabilities van Appium zijn en een basisbegrip hebben van hoe we UI-elementen kunnen identificeren, kunnen we beginnen met het schrijven van tests. In deze blogpost gebruik ik Kotlin.

Stap 1: Afhankelijkheden (Dependencies) importeren

Eerst moeten we een aantal vereiste afhankelijkheden in ons project importeren:

Kotlin

dependencies {
   implementation("io.appium:java-client:8.0.0")
   implementation("org.seleniumhq.selenium:selenium-java:4.1.4")
   implementation("org.testng:testng:7.5")
   testImplementation("org.testng:testng:7.5")
}

Stap 2: De testklasse aanmaken

Voor dit voorbeeld test ik een eenvoudige taken-app die ik heb gemaakt. Maak een nieuwe klasse aan in src/test/kotlin genaamd TodoTasksTest die er als volgt uitziet:

Kotlin

import io.appium.java_client.AppiumBy
import io.appium.java_client.android.AndroidDriver
import org.openqa.selenium.WebDriver
import org.openqa.selenium.remote.DesiredCapabilities
import org.openqa.selenium.support.ui.ExpectedConditions
import org.openqa.selenium.support.ui.WebDriverWait
import org.testng.annotations.AfterTest
import org.testng.annotations.BeforeTest
import org.testng.annotations.Test
import java.net.URL
import java.time.Duration

class TodoTasksTest {
   private lateinit var driver: WebDriver
   private lateinit var waiter: WebDriverWait

   @BeforeTest
   fun setup() {
       // Setup the desired capabilities
       val capabilities = DesiredCapabilities()
       capabilities.setCapability("platformName", "Android")
       capabilities.setCapability("deviceName", "Samsung Galaxy A40")
       capabilities.setCapability("platformVersion", "11")
       capabilities.setCapability("udid", "******")
       capabilities.setCapability("appPackage", "com.coffeeit.appium_example")
       capabilities.setCapability("appActivity", "com.coffeeit.appium_example.MainActivity")
       capabilities.setCapability("noReset", "false")
       capabilities.setCapability("fullReset", "false")

       driver = AndroidDriver(URL("http://127.0.0.1:4723/wd/hub"), capabilities)
       waiter = WebDriverWait(driver, Duration.ofSeconds(10L))
   }

   @Test
   fun testAddTask() {
       // wait for the element to be visible and click on it
       waiter.until(ExpectedConditions.visibilityOfElementLocated(AppiumBy.accessibilityId("AddTask"))).click()

       // if accessibility ids are not defined, we can identify elements in different ways
       val elements = driver.findElements(AppiumBy.className("android.widget.EditText"))
       elements[0].sendKeys("Some title")
       elements[1].sendKeys("Some description")

       // wait for the element to be visible and click on it
       waiter.until(ExpectedConditions.visibilityOfElementLocated(AppiumBy.accessibilityId("SaveTask"))).click()
   }

   @Test
   fun testAddTaskBackButton() {
       // wait for the element to be visible and click on it
       waiter.until(ExpectedConditions.visibilityOfElementLocated(AppiumBy.accessibilityId("AddTask"))).click()

       // wait for the element to be visible and click on it
       waiter.until(ExpectedConditions.visibilityOfElementLocated(AppiumBy.accessibilityId("Back"))).click()
   }

   @AfterTest
   fun teardown() {
       driver.quit()
   }
}

In het bovenstaande voorbeeld beginnen we met het instellen van onze capabilities. Daarna zijn er twee tests gedefinieerd: de ene voegt een nieuwe taak toe met een titel en beschrijving, terwijl de andere op de terugknop drukt wanneer er wordt geprobeerd een taak toe te voegen. In de laatste functie beëindigen we de automatiseringssessie.

De langste stap hier is het instellen van de capabilities en het voorbereiden van het testapparaat. De tests zelf duren slechts een paar seconden.De volgende keer dat we iets willen testen, starten we simpelweg de Appium server, sluiten we ons apparaat aan en voeren we onze tests uit. Maar wat als je geen developer bent? Kun je Appium dan nog steeds gebruiken om tests te schrijven?

Introductie tot TestProject

Appium is een gratis, opensourceframework dat ontworpen is om testen zo veel mogelijk te automatiseren, en dat doet het uitstekend. Je moet echter nog steeds een developer zijn om de tests te kunnen schrijven.

Gelukkig bieden commerciële testautomatiseringsframeworks online omgevingen waarin je apps kunt testen zonder code te schrijven. Je kunt testdata klaarzetten, tests opnemen en ze integreren in cloudoplossingen zoals GitLab CI of AWS.

In 2015 begon een opensource-initiatief om deze premium functies gratis voor de wereld beschikbaar te maken. In april 2018 werd de eerste versie van deze online testomgeving uitgebracht onder de naam TestProject.TestProject is een gratis, end-to-end testautomatiseringsplatform voor web-, mobiele en API-tests dat slim gebruikmaakt van Appium. Het is een zeer krachtig platform dat volledig gratis kan worden gebruikt.

Belangrijke kernoverwegingen

Hoewel TestProject beweert opensource te zijn, zijn in werkelijkheid alleen hun SDK en plug-ins dat. De online omgeving zelf is closed-source. Dit betekent dat je geen lokale instantie van het online dashboard kunt draaien en dat een actieve internetverbinding verplicht is om het te gebruiken.

Hoe gebruik je TestProject?

Het gebruik van TestProject is heel eenvoudig:

  1. Registreer een account en log in.
  2. Volg de installatiewizard en bevestig je e-mailadres.
  3. Stel de TestProject Agent in. Deze agent draait een Appium server op de achtergrond en communiceert rechtstreeks met je testapparaten en emulators.
  4. Eenmaal geconfigureerd, kom je in de testomgeving terecht waar automatisch een standaard testproject wordt aangemaakt om je op weg te helpen.

Navigeren op het TestProject-dashboard

Linksboven op het dashboard zie je je huidige project en kun je naar andere projecten schakelen. De tabbladen eronder beheren je projectspecifieke gegevens:

Tests & Jobs

TestProject verdeelt het werk in tests en jobs. Tests volgen simpelweg een specifieke stroom van stappen, terwijl jobs bestaan uit een of meerdere tests die aan een specifiek apparaat zijn gekoppeld. Jobs kunnen handmatig worden geactiveerd of worden ingepland.

Elements

In het tabblad Elements kun je UI-elementen vooraf definiëren. Dit maakt het schrijven van meerdere tests een stuk eenvoudiger, omdat je er later simpelweg naar kunt verwijzen zonder opnieuw code te hoeven schrijven.

Applications & Data Sources

  • Applications: Definieer de specifieke apps die je wilt testen.
  • Data Sources: Sla externe bestanden op (zoals een CSV-bestand) om de weg vrij te maken voor Data-Driven Tests en Jobs.

Parameters & Devices

  • Parameters: Definieer key/value-parameters op projectniveau (zoals inloggegevens) om ze in verschillende tests te hergebruiken.
  • Devices: Geef autorisatie aan je testhardware. Wanneer de agent een nieuw apparaat herkent, verschijnt er een pop-up voor autorisatie.

Geavanceerde test- & stapconfiguratie

Wanneer je een test opent, wordt alle gerelateerde informatie weergegeven. Je kunt stappen native opnemen (hiervoor moet een lokale TestProject agent actief zijn) of handmatig stappen aanmaken.

Globale versus stap-specifieke instellingen

Het tandwielpictogram linksboven opent de globale testinstellingen. Hier kun je het volgende configureren:

  • Hoe snel de test moet worden uitgevoerd.
  • Wat er gebeurt als een stap mislukt.
  • Of er bij elke stap screenshots moeten worden gemaakt.

Hoewel deze regels globaal gelden, kun je ze binnen TestProject ook op stapniveau overschrijven door de geavanceerde opties van een specifieke individuele stap uit te vouwen.

Binnen het tabblad Steps

Elke stap in een test heeft een specifieke actie die moet worden uitgevoerd. TestProject biedt een breed scala aan ingebouwde opties en ondersteunt add-ons.Add-ons zijn ontzettend handig wanneer je moet communiceren met native UI-elementen buiten je app, en ze kunnen door iedereen in de community worden gemaakt en gedeeld.

Platformrapporten en integraties

Prachtige rapportages

TestProject kan automatisch visueel aantrekkelijke, gedetailleerde testrapporten genereren. Deze lichten de testuitvoering van begin tot eind toe, waarbij de exact gebruikte testdata en uitgevoerde acties worden benadrukt.Samenvattingen en volledige rapporten kunnen eenvoudig worden gedeeld met stakeholders. Als je test is geconfigureerd om bij elke stap screenshots te maken, worden die afbeeldingen rechtstreeks in het volledige rapport gekoppeld.

Integraties van derden

TestProject integreert native met platforms zoals Sauce Labs en BrowserStack, en ondersteunt aangepaste webhooks voor succes- of foutmeldingen.Hoewel TestProject-agents binnen Docker-containers kunnen draaien, moet je er rekening mee houden dat op Docker gebaseerde agents momenteel geen lokale hardware-apparaatherkenning ondersteunen.

API & GitLab CI-pipelines

TestProject beschikt over een omvangrijke API waarmee je eenvoudig tests en jobs op afstand kunt triggeren. Je kunt bijvoorbeeld je eigen aangepaste integratiepipeline schrijven in GitLab CI voor het testen van Android. Deze reeks voert een serie jobs uit en sluit de pipeline pas af wanneer alle taken succesvol zijn afgerond:

YAML

# Minimal OS image with Java and Android 31 build tools pre-installed
image: mreichelt/android:31

variables:
 # Colors for terminal output
 Color_Off: '\e[0m'
 Red: '\e[0;31m'
 Green: '\e[0;32m'
 BRed: '\e[1;31m'
 BGreen: '\e[1;32m'
 BBlue: '\e[1;34m'
 
 # TestProject variables
 TP_API_URL: "https://api.testproject.io/v2"
 TEST_RETRIES: 2
 TP_API_KEY: "SOME_API_KEY"
 TP_PROJECT_ID: "some_project_id"
 TP_APP_ID: "some_app_id"
 TP_APK_FILE_NAME: "app-debug.apk"
 TP_JOBS: "job_id_1 job_id_2"

before_script:
 - apt-get --quiet update --yes
 - apt-get --quiet install jq --yes

stages:
 - build
 - upload
 - test

# Build project
assembleDebug:
 interruptible: true
 stage: build
 script:
   - ./gradlew -Dorg.gradle.jvmargs=-Xmx2048m assembleDebug
 artifacts:
   untracked: true
   paths:
     - app/build/outputs/

# Upload the APK to TestProject
uploadAPK:
 interruptible: true
 stage: upload
 script:
   # Get AWS url from TestProject to upload to
   - 'UPLOAD_DATA=$(curl -s -S -X GET "${TP_API_URL}/projects/${TP_PROJECT_ID}/applications/${TP_APP_ID}/file/upload-link" -H "accept: application/json" -H "Authorization: ${TP_API_KEY}")'
   - echo $UPLOAD_DATA
   # Parse the upload url
   - UPLOAD_URL=$(echo $UPLOAD_DATA | jq -r ".url")
   - UPLOAD_METHOD=$(echo $UPLOAD_DATA | jq -r ".method.Method")
   - echo $UPLOAD_URL
   - echo $UPLOAD_METHOD
   # Upload the APK to the upload url
   - curl "${UPLOAD_URL}" --upload-file app/build/outputs/apk/debug/app-debug.apk
   # Publish the APK to the TestProject app
   - 'UPLOAD_CONFIRM_DATA=$(curl -X POST "${TP_API_URL}/projects/${TP_PROJECT_ID}/applications/${TP_APP_ID}/file" -H "accept: application/json" -H "Authorization: ${TP_API_KEY}" -H "Content-Type: application/json" -d "{ \"fileName\": \"${TP_APK_FILE_NAME}\" }")'

Yassin Amhagi

Veelgestelde vragen

Wat is Appium en waarvoor wordt het gebruikt?

Appium is een open source testautomatiseringsframework voor mobiele apps. Het ondersteunt native, hybride en mobiele webapps en maakt het mogelijk om geautomatiseerde tests te schrijven voor zowel Android als iOS.

Welke programmeertalen kun je gebruiken met Appium?

Met Appium kun je tests schrijven in verschillende programmeertalen zoals Java, Kotlin, JavaScript, Python, Ruby en C#. Dit gebeurt via de Selenium WebDriver API en bijbehorende client libraries.

Wat zijn Desired Capabilities in Appium?

Desired Capabilities zijn configuratie-instellingen die je naar de Appium-server stuurt bij het starten van een testsessie. Hierin geef je onder andere aan welk apparaat, besturingssysteem en welke app getest moet worden.

Waarom zijn accessibility ID’s belangrijk bij het schrijven van mobiele tests?

Accessibility ID’s maken het mogelijk om UI-elementen stabiel en platformonafhankelijk te identificeren. Hierdoor kun je vaak dezelfde test gebruiken voor zowel Android als iOS, wat onderhoud en ontwikkeling efficiënter maakt.

Wat is het verschil tussen Appium en TestProject?

Appium vereist programmeerkennis om tests te schrijven en te beheren. TestProject bouwt voort op Appium en biedt een gebruiksvriendelijke online omgeving waarmee ook niet-developers geautomatiseerde tests kunnen opzetten, beheren en rapporteren.

Gerelateerde blogs