Testarea UI verifică corectitudinea afișării și interacțiunii elementelor interfeței de utilizator a aplicației mobile — butoane, câmpuri de text, liste și componente de navigare. Spre deosebire de testele unitare care verifică logica de afaceri, testele UI emulează acțiunile utilizatorului: atingeri, glisări, introducere de text și verifică reacția interfeței. Conform studiului Android Developers, 2024, testarea UI acoperă 70% din scenariile critice ale utilizatorului și permite detectarea defectelor de layout care nu sunt accesibile verificărilor logice.
Principalele
Testarea UI este un tip de verificare automatizată în care codul de test interacționează cu interfața grafică a aplicației exact așa cum ar face un utilizator real. Testul găsește pe ecran un element — buton, câmp de text, listă — execută o acțiune asupra lui și verifică reacția așteptată a interfeței. De exemplu, după introducerea unei parole incorecte, testul UI verifică dacă pe ecran a apărut un mesaj de eroare cu textul corect.
Principala diferență între testele UI și alte tipuri de automatizare este că acestea funcționează prin stratul Accessibility al sistemului de operare, nu prin API-urile interne ale aplicației. Aceasta înseamnă că testele UI văd interfața exact așa cum o vede utilizatorul și sistemul de citire a ecranului. Datorită acestui fapt, testele UI verifică nu doar funcționalitatea, ci și accesibilitatea elementelor — conformitatea cu cerințele WCAG.
Conform sondajului JetBrains Developer Ecosystem 2023, 58% dintre echipele mobile utilizează teste UI în pipeline-ul lor CI/CD. Acoperirea medie cu teste UI în proiectele comerciale este de 30–40% din ecranele aplicației. Proiectele cu teste UI primesc cu 25% mai puține recenzii negative în magazinele de aplicații legate de crash-uri ale interfeței.
Principala diferență între testele UI și testele unitare este nivelul de abstractizare. Testele unitare lucrează cu clase și funcții individuale, izolate de framework-ul Android sau iOS. Ele se execută pe JVM (pentru Android) fără a porni emulatorul și durează milisecunde. Testele UI rulează pe un dispozitiv real sau emulator, interacționează cu serviciile de sistem și necesită secunde sau minute pentru un singur scenariu.
Diferă și audiența țintă a testelor. Testele UI verifică scenarii complete ale utilizatorului — înregistrare, plasare comandă, căutare. Testele unitare acoperă logica de afaceri: calcule, validare, transformare de date. Un test UI nu verifică corectitudinea calculului fiscal — el verifică dacă suma finală este afișată pe ecran. Calculul în sine este verificat de un test unitar.
Conform Google Testing Blog (2020), raportul optim al testelor într-un proiect ar trebui să urmeze regula piramidei de testare: 70% teste unitare, 20% teste de integrare și 10% teste UI. Încălcarea acestui raport în favoarea testelor UI duce la creșterea timpului de execuție și fragilitatea setului de teste, deoarece testele UI sunt sensibile la modificările din layout-ul ecranelor.
Pentru Android, framework-ul dominant este Espresso — o bibliotecă de la Google încorporată în AndroidX Test. Espresso se sincronizează automat cu firul UI, așteptând finalizarea animațiilor și a sarcinilor de fundal înainte de a efectua următoarea verificare. Pentru Jetpack Compose se utilizează extensia Compose UI Test, care funcționează prin noduri semantice în locul identificatorilor tradiționali de vizualizare.
Pentru iOS, instrumentul principal este XCUITest, inclus în componența Xcode. Testele se scriu în Swift și utilizează identificatori Accessibility pentru găsirea elementelor. XCUITest suportă înregistrarea testelor prin funcția record și integrarea cu sistemele CI prin xcodebuild. Pentru proiectele cross-platform se utilizează Appium, bazat pe protocolul WebDriver, care permite rularea acelorași teste pe Android și iOS cu modificări minime în cod.
Espresso lucrează cu sistemul View tradițional prin onView și identificatori de resurse id. Compose UI Test utilizează un strat semantic, ceea ce face testele mai puțin dependente de ierarhia vizualizărilor. De exemplu, căutarea unui buton în Espresso: onView(withId(R.id.submit)), în Compose: onNodeWithTag(„submit”). Testele Compose gestionează automat recompoziția și nu necesită așteptări explicite pentru starea de inactivitate.
XCUITest utilizează XCUIApplication ca punct de intrare. Fiecare element al interfeței este căutat prin proprietățile Accessibility: accessibilityIdentifier pentru acces programatic și accessibilityLabel pentru VoiceOver. Framework-ul suportă înregistrarea testelor prin funcția record din Xcode — dezvoltatorul execută acțiuni pe simulator, iar Xcode generează codul testului. Testele gata sunt rulate prin xcodebuild test.
Appium se bazează pe protocolul WebDriver și suportă orice limbaj: Java, Python, JavaScript. Pentru găsirea elementelor se utilizează strategiile id, xpath, class name și accessibility id. Appium necesită instalarea unui server și configurarea Desired Capabilities — platformName, deviceName, appPackage. O alternativă este Maestro, care utilizează scenarii YAML și nu necesită compilarea codului de test.
Să analizăm testele UI pentru același scenariu — autentificarea în aplicație — în trei framework-uri diferite: Espresso pentru Android, XCUITest pentru iOS și Appium pentru abordarea cross-platform. Scenariul: introduceți numele de utilizator și parola, apăsați butonul de autentificare, verificați afișarea mesajului de bun venit.
Testul în Espresso utilizează onView pentru găsirea elementului după identificator și perform pentru executarea acțiunii. Metoda check cu matcher-ul isDisplayed confirmă că elementul este vizibil pe ecran.
@RunWith(AndroidJUnit4::class)
class LoginUiTest {
@Rule
@JvmField
val composeTestRule = createComposeRule()
@Test
fun login_withValidCredentials_showsWelcome() {
composeTestRule
.onNodeWithTag("emailField")
.performTextInput("user@example.com")
composeTestRule
.onNodeWithTag("passwordField")
.performTextInput("secret123")
composeTestRule
.onNodeWithTag("loginButton")
.performClick()
composeTestRule
.onNodeWithText("Bun venit, Utilizatorule!")
.assertIsDisplayed()
}
}
XCUITest utilizează XCUIApplication pentru accesarea elementelor interfeței prin identificatori Accessibility. Metodele tap() și exists asigură interacțiunea și verificarea.
class LoginUITests: XCTestCase {
let app = XCUIApplication()
override func setUp() {
continueAfterFailure = false
app.launch()
}
func testLogin_withValidCredentials_showsWelcome() {
app.textFields["emailField"].tap()
app.textFields["emailField"].typeText("utilizator@example.com")
app.secureTextFields["passwordField"].tap()
app.secureTextFields["passwordField"].typeText("secret123")
app.buttons["loginButton"].tap()
XCTAssertTrue(app.staticTexts["Welcome, User!"].exists)
}
}
Primul principiu — utilizați identificatori Accessibility în locul etichetelor text pentru găsirea elementelor. Textul butonului se poate schimba la localizare, în timp ce identificatorul rămâne stabil. În Android aceasta este proprietatea contentDescription, în iOS — accessibilityIdentifier. Această abordare face testele independente de limba interfeței și reduce costurile de întreținere la modificarea copywriting-ului.
Evitați sleep() și întârzierile fixe — utilizați mecanismele de așteptare încorporate ale framework-ului. Espresso așteaptă automat finalizarea animațiilor și a sarcinilor de fundal. XCUITest oferă XCTAssertTrue cu timeout. Pauzele explicite încetinesc testele și le fac mai puțin stabile, în special pe dispozitive lente în mediul CI.
Grupați testele după criticitate: testele smoke (3–5 scenarii cheie) se rulează la fiecare commit, setul complet de teste UI — înainte de lansare. Conform Google Testing Blog (2022), testele UI care durează mai mult de 30 de minute în CI reduc frecvența de rulare cu 40%, ceea ce scade eficiența lor ca instrument de detectare timpurie a regresiunilor.
Testele UI au o serie de limitări. Sensibilitatea la modificările de layout: schimbarea identificatorului, a ierarhiei sau a tipului de element strică testul chiar și cu funcționalitate neschimbată. Soluția — utilizarea pattern-ului Page Object, care centralizează selectorii de elemente în clase separate. La modificarea layout-ului, se corectează un singur fișier Page Object, nu zeci de teste.
Timpul de execuție: rularea pe un dispozitiv real sau emulator durează de 10–50 de ori mai mult decât un test unitar. Soluția — rularea paralelă a testelor UI pe mai multe dispozitive prin Firebase Test Lab sau AWS Device Farm. Instabilitatea (flakiness) — o problemă frecventă a rulărilor CI, cauzată de animații, întârzieri de rețetea sau starea emulatorului. Pentru combaterea flakiness-ului se aplică reîncercarea automată a testelor eșuate și analiza de stabilitate a fiecărui scenariu de test.
Întrebări frecvente
Pentru un ecran mediu sunt suficiente 3–5 teste UI: happy path, validarea erorilor, stare goală, schimbarea orientării și verificarea Accessibility. Ecranele complexe cu multiple stări — formulare de comandă, setări — pot necesita 10–15 teste pentru acoperirea completă a scenariilor cheie.
Da, Appium și Maestro permit rularea acelorași scenarii pe ambele platforme. Cu toate acestea, framework-urile native — Espresso și XCUITest — oferă o stabilitate, viteză și acces mai bune la capacitățile platformei care nu sunt disponibile prin proxy-ul WebDriver.
Pentru Compose se utilizează biblioteca Compose UI Test cu matcher-e semantice: onNodeWithText, onNodeWithTag, onNodeWithContentDescription. Stratul semantic al Compose abstractizează ierarhia vizualizărilor, ceea ce face testele mai puțin fragile în comparație cu Espresso tradițional pentru sistemul View.
Rularea de bază a testelor UI se efectuează pe emulatoare în CI — este rapidă și ieftină. Verificarea finală înainte de lansare se recomandă a fi efectuată pe dispozitive fizice prin Firebase Test Lab pentru a lua în considerare particularitățile hardware-ului real: rezoluții diferite, versiuni de sistem de operare și performanță.
Utilizați rularea paralelă pe mai multe dispozitive, dezactivați animațiile pe emulator prin Developer Options, construiți o arhitectură modulară a testelor și rulați setul smoke la fiecare commit, iar setul complet de regresie — conform unui program sau înainte de lansare.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și