Code Coverage (acoperirea codului) este o metrică care arată ce procent din codul sursă al aplicației este executat în timpul testării. Ajută la determinarea calității testelor, identificarea zonelor neverificate și prioritizarea scrierii de noi teste. Potrivit Atlassian, 2025, nivelul optim de acoperire este de 70–80% — peste acest prag, costurile testelor încep să depășească beneficiile.
Puncte cheie
Code Coverage (acoperirea codului) este o metrică cantitativă care determină ce parte din codul sursă al aplicației a fost executată în timpul testelor. Se exprimă în procente și se calculează ca raportul dintre numărul de linii/ramuri executate și numărul total. Acoperirea ridicată nu garantează absența bug-urilor, dar reduce riscul de erori omise.
Acoperirea codului ajută echipa: să găsească zonele netestate ale codului, să ia decizii privind prioritățile scrierii testelor, să urmărească dinamica calității testării în CI/CD. În dezvoltarea mobilă, acoperirea este deosebit de importantă pentru logica de business, modelele de date și depozite — straturile cu cea mai mare probabilitate de erori.
Un mit răspândit: „100% acoperire = calitate ideală”. În practică, 100% acoperire se atinge extrem de rar și adesea cu prețul unor teste superficiale. Acoperirea eficientă nu este o cursă pentru procent, ci o acoperire strategică a căilor critice și a condițiilor limită. Acoperirea nu spune nimic despre calitatea testelor în sine: un test poate trece, dar să nu verifice corectitudinea rezultatului.
Există mai multe metrici Code Coverage, fiecare măsurând diferite aspecte ale testării. Line coverage (acoperirea liniilor) — cea mai simplă metrică, care arată procentul liniilor de cod executate. Branch coverage (acoperirea ramurilor) măsoară care ramificări if-else și switch au fost testate.
Line coverage numără fiecare linie de cod sursă ca executată sau nu. Dacă într-o linie se află un operator condițional sau o buclă, linia este considerată executată dacă controlul a ajuns la ea, chiar dacă nu toate ramurile au fost procesate. Este cea mai puțin strictă metrică, dar cea mai ușor de înțeles pentru evaluarea vizuală.
Branch coverage evaluează dacă toate ramificările posibile din cod au fost testate. Pentru fiecare if-else se iau în considerare ambele ramuri: true și false. Pentru switch — fiecare case. Branch coverage este considerată o metrică mai strictă decât line coverage și identifică mai frecvent scenariile netestate.
| Metrică | Ce măsoară | Dificultatea atingerii |
|---|---|---|
| Line | Procentul liniilor de cod executate | Scăzută |
| Branch | Procentul ramificărilor executate (if/else, switch) | Medie |
| Function | Procentul funcțiilor și metodelor apelate | Scăzută |
| Condition | Procentul subexpresiilor logice (&&, ||) | Ridicată |
Path coverage — cea mai strictă metrică, care necesită verificarea tuturor combinațiilor posibile de ramificări dintr-o funcție. În practică, path coverage este rar folosită din cauza creșterii exponențiale a numărului de combinații: o funcție cu 10 ramificări are 1024 de căi posibile.
În dezvoltarea mobilă se folosesc diverse instrumente pentru măsurarea Code Coverage în funcție de platformă. Pentru Android, standardul este JaCoCo (Java Code Coverage), care se integrează cu Gradle și suportă atât testele unitare, cât și testele instrumentale. Pentru iOS se folosește XCCov, încorporat în Xcode.
JaCoCo generează rapoarte în formate HTML, XML și CSV. Raportul HTML evidențiază vizual liniile: verde — executate, roșu — omise, galben — parțial executate. Raportul XML este compatibil cu SonarQube și alte sisteme de analiză a codului. JaCoCo suportă filtrarea claselor: se poate exclude codul generat, databinding, BuildConfig.
// build.gradle — configurarea JaCoCo
android {
buildTypes {
debug {
testCoverageEnabled = true
}
}
}
// Crearea raportului JaCoCo
task jacocoTestReport(type: JacocoReport) {
dependsOn 'testDebugUnitTest'
reports {
xml.enabled = true
html.enabled = true
}
}
XCCov — instrumentul încorporat al Xcode pentru măsurarea acoperirii codului. Se activează prin Gather coverage data în schema de testare. XCCov suportă acoperirea pentru Swift și Objective-C, generează rapoarte în .xccovreport și se integrează cu CI prin xcodebuild -enableCodeCoverage YES. Datele sunt afișate în consolă și pot fi exportate în JSON.
Pentru monitorizarea centralizată a acoperirii se folosesc platforme: SonarQube (analiza calității codului + acoperire), Codecov și Coveralls. Aceste servicii agregă datele din JaCoCo și XCCov, arată tendințele, Quality Gate și integrarea cu GitHub/GitLab prin comentarii PR.
Creșterea Code Coverage necesită o abordare sistematică: nu „atingem procentele”, ci acoperim riscurile. Primul pas este analiza raportului JaCoCo sau XCCov — identificarea claselor roșii (neacoperite). Prioritate: logica de business → depozite → ViewModel → componente UI.
Test-Driven Development (TDD) asigură automat o acoperire ridicată, deoarece testele se scriu înaintea implementării. Proces: roșu (scrie un test care eșuează) → verde (scrie codul minim) → refactorizare. TDD disciplinează dezvoltatorul, forțând acoperirea cazurilor limită și a situațiilor excepționale care rămân adesea netestate.
Un singur test parametrizat înlocuiește zeci de teste obișnuite. JUnit și XCTest suportă parametrizarea: @ParameterizedTest în JUnit 5, XCTestCase cu testPerformanceExample în XCTest. Parametrizarea permite verificarea mai multor date de intrare fără duplicarea codului, ceea ce extinde semnificativ acoperirea ramurilor și condițiilor.
// Test parametrizat în Kotlin cu JUnit 5
@ParameterizedTest
@ValueSource(strings = ["user@test.com", "admin@test.com", "test@example.com"])
fun `validate email returns true for valid addresses`(email: String) {
val result = EmailValidator.isValid(email)
Assertions.assertTrue(result)
}
Cea mai frecventă greșeală — cursa după procent fără analiza calității testelor. Echipa începe să scrie teste de dragul testelor: verifică getter-e și setter-e, dublează acoperirea la diferite niveluri, testează metode triviale. Acest lucru dă un procent ridicat, dar nu crește calitatea reală.
Un Code Coverage ridicat poate crea impresia iluzorie că aplicația este bine testată. Un test poate executa o linie de cod, dar să nu verifice corectitudinea rezultatului. De exemplu: testul apelează metoda de calcul a discountului, dar nu verifică suma — linia este executată, acoperirea crește, dar bug-ul nu este găsit.
Greșeala tipică — testarea doar a „căii fericite” (happy path) și ignorarea cazurilor limită: liste goale, valori null, numere maxime, formate incorecte. Majoritatea bug-urilor apar exact la limite și în excepții. Branch coverage ajută la identificarea ramurilor omise, dar nu garantează verificarea valorilor limită.
Mutation Testing este o metodă de evaluare a calității testelor în care se introduc mutații (erori artificiale) în codul sursă și se verifică dacă testele eșuează. Pitest — instrument popular de mutation testing pentru Java și Kotlin. Dacă testele nu au eșuat pe mutație — înseamnă că nu verifică acea condiție.
Pitest creează mutanți — copii modificate ale codului sursă, în care, de exemplu, > este înlocuit cu >=, true cu false sau este eliminat un apel de metodă. Apoi pentru fiecare mutant se rulează testele. Dacă testele trec — mutantul a supraviețuit, înseamnă că testele nu acoperă acest scenariu. Dacă testele eșuează — mutantul a fost ucis, testul este corect.
// build.gradle — configurarea Pitest
plugins {
id 'info.solidsoft.pitest' version '1.15.0'
}
pitest {
targetClasses = ['com.example.app.*']
targetTests = ['com.example.app.*Test']
threads = 4
outputFormats = ['HTML', 'XML']
mutationThreshold = 80
coverageThreshold = 85
}
Pitest suportă multiple tipuri de mutații: modificarea operatorilor condiționali (== → !=, < → <=), eliminarea apelurilor de metode, înlocuirea valorilor returnate (true → false), modificarea operațiilor aritmetice (+ → -), mutația incrementării (i++ → i--). Cu cât mai multe tipuri de mutații sunt ucise de teste, cu atât setul de teste este mai fiabil.
Scorul de mutație țintă — 80% și peste. Aceasta înseamnă că 80% din erorile artificiale au fost detectate de teste. Acoperirea codului (Code Coverage) de 90% nu garantează că testele găsesc erori — mutation testing oferă o evaluare mai obiectivă. Pitest poate fi integrat în CI ca Quality Gate, blocând build-ul la scăderea scorului de mutație sub prag.
Pentru controlul automat al Code Coverage în CI/CD se folosesc Quality Gates — valori prag, la încălcarea cărora build-ul este marcat ca instabil sau respins. SonarQube permite configurarea Quality Gate pe baza unei combinații de metrici: acoperire (≥80%), numărul de bug-uri, vulnerabilități și cod duplicat.
În GitHub Actions, Code Coverage se integrează prin pași de acțiune: rularea testelor cu acoperire → încărcarea raportului în Codecov → verificarea pragului. Codecov comentează automat PR-ul cu diff-ul acoperirii, arătând care linii s-au schimbat și cum au afectat procentul general. Dacă acoperirea a scăzut — PR-ul este blocat până la scrierea de teste suplimentare.
# GitHub Actions — încărcarea acoperirii în Codecov
- name: Run Tests with Coverage
run: ./gradlew testDebugUnitTest jacocoTestReport
- name: Upload to Codecov
uses: codecov/codecov-action@v4
with:
files: ./app/build/reports/jacoco/jacocoTestReport.xml
flags: unittests
fail_ci_if_error: true
- name: Check Coverage Threshold
run: |
coverage=$(grep -oP 'branchCoverage="\K[0-9.]+' report.xml)
if (( $(echo "$coverage < 80" | bc -l) )); then
echo "Coverage $coverage% is below 80% threshold"
exit 1
fi
Rapoartele HTML JaCoCo și XCCov conțin evidențierea vizuală a acoperirii: verde — linii executate, roșu — neexecutate. SonarQube arată suplimentar acoperirea la nivel de fișier, clasă, metodă și linie, precum și istoricul modificărilor acoperirii pe sprinturi. Acest lucru ajută la luarea deciziilor privind refactorizarea și adăugarea de teste.
Întrebări frecvente
Pentru proiectele mobile, o acoperire de 70–80% pentru logica de business și 50–60% pentru componentele UI este considerată bună. Peste 80%, costurile testării încep să depășească beneficiile. Este important să reținem că procentul nu este un scop, ci un indicator, iar diferite module pot avea niveluri țintă diferite.
Line Coverage arată câte linii de cod au fost executate. Branch Coverage — câte ramificări (if-else, switch) au fost testate. O linie cu if poate fi executată, dar ramura true testată, iar false — nu. Branch Coverage este mai strict și identifică mai multe scenarii omise.
În CI/CD, acoperirea se integrează prin Quality Gate: build-ul este blocat dacă acoperirea este sub prag. Pentru Android se folosește JaCoCo + SonarQube, pentru iOS — xcodebuild -enableCodeCoverage cu parsarea .xccovreport. GitHub Actions are acțiuni gata făcute pentru Codecov.
Da, JaCoCo suportă Jetpack Compose prin mecanismul standard de acoperire JVM. Cu toate acestea, codul Compose conține multe expresii lambda generate pe care JaCoCo poate să nu le acopere complet. Se recomandă excluderea codului compose generat din raport prin filtre.
Acoperirea falsă apare atunci când testul execută codul, dar nu verifică rezultatul. Soluție: scrieți verificări assert pentru fiecare scenariu important, utilizați mutation testing (Pitest) pentru a verifica calitatea testelor, analizați nu doar procentul, ci și care ramuri sunt acoperite.
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