Testarea de integrare verifică corectitudinea interacțiunii între componentele aplicației mobile — module, servicii, baze de date și API-uri externe. Spre deosebire de testele unitare, care izolează fiecare componentă, testele de integrare detectează erori la intersecții: incompatibilitatea formatelor de date, defecțiuni la transmiterea parametrilor și procesarea incorectă a răspunsurilor de la server. Conform datelor Martin Fowler, 2018, testele de integrare acoperă până la 40% din defectele critice omise de verificările unitare și asigură încrederea în stabilitatea sistemului înainte de lansare.
Principalele puncte
Testarea de integrare — este etapa de verificare a software-ului în care se evaluează corectitudinea interacțiunii între modulele sau subsistemele individuale ale aplicației. În timp ce testele unitare verifică fiecare componentă în mod izolat, testele de integrare adună aceste componente împreună și verifică cum funcționează în combinație. Scenariile tipice includ transferul de date între stratul de rețea și depozit, scrierea în baza de date prin ORM și procesarea răspunsurilor de la API-uri terțe.
În contextul dezvoltării mobile, testele de integrare acoperă interacțiunea dintre stratul UI, logica de afaceri și sursele de date. De exemplu, un test poate verifica că după apăsarea butonului „Autentificare", aplicația trimite o cerere la server, primește un token și îl salvează în stocarea locală. O astfel de verificare confirmă că lanțul de componente funcționează fără defecțiuni.
Conform raportului World Quality Report 2023, companiile care aplică testarea de integrare în mod regulat reduc numărul incidentelor de producție cu 35% comparativ cu proiectele care se bazează doar pe teste unitare. Acest lucru face ca verificările de integrare să fie un element obligatoriu al strategiei de asigurare a calității în dezvoltarea comercială.
Aplicațiile mobile constau din numeroase componente interconectate: cereri de rețea, baze de date locale, notificări push, servicii de sistem și SDK-uri terțe. Fiecare dintre aceste componente este dezvoltată separat, dar în timpul execuției ele fac schimb de date în timp real. Testarea de integrare detectează defecte care nu pot fi găsite la verificarea izolată a modulelor.
Printre problemele tipice descoperite de testele de integrare se numără nepotrivirea tipurilor de date între API și modelul aplicației, erori de serializare JSON, procesarea incorectă a timeout-urilor de rețea și defecțiuni la accesul concurent la baza de date prin Room sau Core Data. Fără verificări de integrare, astfel de defecte ajung în producție și se manifestă doar la utilizatorii reali.
Cercetarea Google Testing Blog (2021) arată că costul remedierii unui defect descoperit în etapa de testare a integrării este de 5 ori mai mic decât după lansare. Acest lucru se explică prin faptul că în stadiile incipiente, dezvoltatorul are contextul complet al erorii și o poate remedia fără un ciclu urgent de hotfix. Investiția de timp în scrierea testelor de integrare se amortizează prin reducerea costurilor de întreținere și creșterea încrederii utilizatorilor.
Există trei abordări principale de organizare a testelor de integrare: Big Bang, Bottom-Up și Top-Down. Alegerea strategiei depinde de dimensiunea proiectului, arhitectura aplicației și disponibilitatea componentelor la momentul scrierii testelor. Fiecare abordare are avantajele și limitările sale care trebuie luate în considerare la planificarea acoperirii testelor.
Big Bang — abordare în care toate componentele sistemului sunt conectate simultan, după care se execută o rulare generală a testelor. Această metodă este simplă de implementat: nu necesită scrierea de stub-uri sau emularea modulelor individuale. Cu toate acestea, la detectarea unei erori este dificil de determinat care componentă este sursa acesteia. Big Bang este justificat în proiecte mici cu arhitectură simplă, unde numărul de module nu depășește cinci.
Bottom-Up — strategie în care testarea de integrare începe cu componentele de nivel inferior: baza de date, stratul de rețea, serviciile de sistem. După verificarea fiecărui nivel, testele conectează treptat modulele superioare — depozite, clase Use Case și ViewModel. Principalul avantaj este detectarea timpurie a defectelor în straturile fundamentale ale aplicației, ceea ce reduce riscul de erori în cascadă în etapele ulterioare ale dezvoltării.
Top-Down — abordare în care testarea începe cu componentele de nivel superior — ecranele UI și navigarea, iar modulele inferioare sunt imitate cu ajutorul stub-urilor sau mock-urilor. Acest lucru permite verificarea scenariilor de utilizator înainte ca partea de server sau baza de date să fie complet implementate. Top-Down este deosebit de util în dezvoltarea paralelă a părților client și server, când backend-ul nu este încă pregătit pentru integrarea reală.
Pentru testarea de integrare a aplicațiilor mobile se utilizează o serie de instrumente specializate care se împart în trei categorii: biblioteci pentru emularea serverelor, framework-uri pentru lucrul cu baze de date și mijloace de verificare a serviciilor de sistem. Alegerea instrumentului specific depinde de platformă — Android sau iOS — și de stiva tehnologică a proiectului.
Să examinăm exemple practice de teste de integrare pentru Android și iOS. Pentru platforma Android folosim MockWebServer împreună cu JUnit, iar pentru iOS — XCTest cu biblioteca OHHTTPStubs. Ambele exemple verifică scenariul de obținere a datelor de la API și salvarea lor într-un depozit local.
Acest test verifică că cererea Retrofit către serverul emulat returnează JSON corect, iar depozitul transformă răspunsul într-un model de domeniu. MockWebServer interceptează cererea și returnează JSON-ul specificat, după care testul compară rezultatul așteptat cu cel real.
class UserRepositoryTest {
private val mockServer = MockWebServer()
@Before
fun setup() {
mockServer.start()
}
@Test
fun fetchUser_returnsCorrectData() {
val json = "{ \`"id\`": 1, \`"name\`": \`"Alice\`" }"
mockServer.enqueue(MockResponse()
.setBody(json)
.setResponseCode(200))
val repository = UserRepository(
createRetrofit(mockServer.url("/").toString()))
val user = repository.fetchUser(1)
assertEquals(1, user.id)
assertEquals("Alice", user.name)
}
@After
fun tearDown() {
mockServer.shutdown()
}
}
Pentru iOS, un test similar folosește OHHTTPStubs pentru interceptarea cererilor URL. Biblioteca înlocuiește răspunsul serverului la nivelul framework-ului de sistem URL Loading System, permițând testarea oricărei biblioteci de rețea — URLSession, Alamofire sau Moya.
import XCTest
import OHHTTPStubs
import OHHTTPStubsSwift
class UserRepositoryTests: XCTestCase {
func testFetchUser_returnsCorrectData() {
stub(condition: isPath("/users/1")) { _ in
return HTTPStubsResponse(
jsonObject: ["id": 1, "name": "Alice"],
statusCode: 200,
headers: nil
)
}
let repository = UserRepository()
let expectation = expectation(description: "fetch user")
repository.fetchUser(id: 1) { user in
XCTAssertEqual(user.id, 1)
XCTAssertEqual(user.name, "Alice")
expectation.fulfill()
}
waitForExpectations(timeout: 2.0)
}
}
Testarea eficientă a integrării necesită respectarea unor practici care cresc stabilitatea testelor și reduc costurile de întreținere a acestora. Izolați dependențele externe: utilizați baze de date in-memory în locul instanțelor de producție și emulați API-urile externe prin intermediul bibliotecilor de stub-uri de test. Acest lucru elimină defecțiunile nedeterministe cauzate de disponibilitatea rețelei sau starea serviciilor externe.
Mențineți independența testelor: fiecare test de integrare trebuie să funcționeze izolat, fără dependență de rezultatele altor teste. Utilizați adnotările @Before și @After în JUnit sau setUp și tearDown în XCTest pentru pregătirea și curățarea mediului de testare. Acest lucru previne influența reciprocă a testelor și simplifică diagnosticarea erorilor.
Acoperiți cazurile limită: testele de integrare trebuie să verifice nu doar scenariile de succes (happy path), ci și gestionarea erorilor — timeout-uri, coduri HTTP 4xx și 5xx, răspunsuri goale, JSON deteriorat. Conform datelor Google Testing Blog (2022), 60% din incidentele de producție sunt legate de gestionarea incorectă a cazurilor limită care nu au fost acoperite de teste.
Întrebări frecvente
Testele unitare verifică o singură clasă sau funcție în izolare, înlocuind dependențele cu stub-uri. Testele de integrare verifică interacțiunea mai multor componente reale — de exemplu, conexiunea de rețea și baza de date simultan.
Rularea testelor de integrare durează de obicei între 2 și 15 minute, în funcție de numărul de teste și complexitatea mediului. Pentru proiecte mari, se recomandă împărțirea testelor în joburi paralele în sistemul CI pentru a reduce timpul total de verificare înainte de merge.
În primul rând, testele de integrare se scriu pentru stratul de rețea, baza de date și serviciile de sistem — notificări, cameră, geolocalizare. Cererile API către backend și operațiile cu stocarea locală oferă cel mai mare ROI, deoarece aceste componente devin cel mai des surse de regresii.
Pentru un singur ecran, sunt suficiente testele unitare ViewModel și testele UI. Testele de integrare pentru un singur ecran sunt justificate doar dacă ecranul interacționează cu mai multe surse de date — de exemplu, combină răspunsuri de la două API-uri diferite sau scrie date simultan în rețea și în baza de date locală.
Testele de integrare se rulează la fiecare pull request în pipeline-ul CI și înainte de lansările principale. De asemenea, se recomandă rularea setului complet de teste de integrare pe timp de noapte (nightly build) pentru a detecta defecte legate de modificări în dependențe sau mediul de testare.
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