Интеграционо тестирање проверава коректност интеракције између компонената мобилне апликације — модула, сервиса, база података и спољних API-ја. За разлику од јединичних тестова који изолују сваку компоненту, интеграциони тестови откривају грешке на спојевима: некомпатибилност формата података, отказе при преносу параметара и некоректну обраду одговора са сервера. Према подацима Martin Fowler, 2018, интеграциони тестови покривају до 40% критичних дефеката пропуштених јединичним проверама и обезбеђују поверење у стабилност система пре објављивања.
Главно
Интеграционо тестирање — је фаза провере софтвера у којој се процењује коректност интеракције између појединачних модула или подсистема апликације. Док јединични тестови проверавају сваку компоненту изоловано, интеграциони тестови састављају ове компоненте заједно и проверавају како раде у спрези. Типични сценарији укључују пренос података између мрежног слоја и репозиторијума, упис у базу података преко ORM-а и обраду одговора од спољних API-ја.
У контексту мобилног развоја, интеграциони тестови покривају интеракцију између UI слоја, пословне логике и извора података. На пример, тест може проверити да након притиска на дугме „Пријава" апликација шаље захтев серверу, добија токен и чува га у локалном складишту. Таква провера потврђује да ланац компонената ради без отказа.
Према извештају World Quality Report 2023, компаније које редовно примењују интеграционо тестирање смањују број производних инцидената за 35% у поређењу са пројектима који се ослањају само на јединичне тестове. То чини интеграционе провере обавезним елементом стратегије обезбеђења квалитета у комерцијалном развоју.
Мобилне апликације се састоје од бројних међусобно повезаних компонената: мрежних захтева, локалних база података, push обавештења, системских сервиса и спољних SDK-јева. Свака од ових компонената се развија одвојено, али у радном времену оне размењују податке у реалном времену. Интеграционо тестирање открива дефекте који се не могу открити при изолованој провери модула.
Међу типичним проблемима које откривају интеграциони тестови су неусклађеност типова података између API-ја и модела апликације, грешке серијализације JSON-а, некоректна обрада мрежних тајмаута и откази при паралелном приступу бази података путем Room-а или Core Data-е. Без интеграционих провера, такви дефекти доспевају у продукцију и манифестују се само код стварних корисника.
Истраживање Google Testing Blog (2021) показује да је цена исправке дефекта откривеног у фази интеграционог тестирања 5 пута нижа него након објављивања. То се објашњава чињеницом да у раним фазама програмер има пун контекст грешке и може је исправити без хитног hotfix циклуса. Улагање времена у писање интеграционих тестова се исплати кроз смањење трошкова одржавања и повећање поверења корисника.
Постоје три главна приступа организовању интеграционих тестова: Big Bang, Bottom-Up и Top-Down. Избор стратегије зависи од величине пројекта, архитектуре апликације и доступности компонената у тренутку писања тестова. Сваки приступ има своје предности и ограничења која је важно узети у обзир при планирању тест покривености.
Big Bang — приступ у којем се све компоненте система истовремено повезују, након чега се извршава општи тест прогон. Овај метод је једноставан за имплементацију: не захтева писање заглушки или емулацију појединачних модула. Међутим, при откривању грешке тешко је одредити која је компонента њен извор. Big Bang је оправдан у малим пројектима са једноставном архитектуром, где број модула не прелази пет.
Bottom-Up — стратегија у којој интеграционо тестирање почиње од нискоризичних компонената: базе података, мрежног слоја, системских сервиса. Након провере сваког нивоа, тестови постепено повезују више модуле — репозиторијуме, Use Case класе и ViewModel. Главна предност је рано откривање дефеката у фундаменталним слојевима апликације, што смањује ризик од каскадних грешака у каснијим фазама развоја.
Top-Down — приступ у којем тестирање почиње од компонената горњег нивоа — UI екрана и навигације, а нижи модули се имитирају помоћу заглушки или мокова. То омогућава проверу корисничких сценарија пре него што су серверски део или база података у потпуности имплементирани. Top-Down је посебно користан при паралелном развоју клијентског и серверског дела, када бекенд још није спреман за стварну интеграцију.
За интеграционо тестирање мобилних апликација користи се низ специјализованих алата који се деле у три категорије: библиотеке за емулацију сервера, оквири за рад са базама података и средства за проверу системских сервиса. Избор конкретног алата зависи од платформе — Android или iOS — и технолошког стека пројекта.
Размотримо практичне примере интеграционих тестова за Android и iOS. За платформу Android користимо MockWebServer у спрези са JUnit, а за iOS — XCTest са библиотеком OHHTTPStubs. Оба примера проверавају сценариј добијања података од API-ја и њиховог чувања у локалном репозиторијуму.
Овај тест проверава да Retrofit захтев ка емулираном серверу враћа исправан JSON, а репозиторијум претвара одговор у доменски модел. MockWebServer пресреће захтев и враћа задати JSON, након чега тест упоређује очекивани резултат са стварним.
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()
}
}
За iOS сличан тест користи OHHTTPStubs за пресретање URL захтева. Библиотека замењује одговор сервера на нивоу системског оквира URL Loading System, што омогућава тестирање било које мрежне библиотеке — URLSession, Alamofire или 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)
}
}
Ефикасно интеграционо тестирање захтева поштовање низа пракси које повећавају стабилност тестова и смањују трошкове њиховог одржавања. Изолујте спољне зависности: користите in-memory базе података уместо продукцијских инстанци и емулирајте спољне API-је путем библиотека тест заглушки. То елиминише недетерминистичке отказе узроковане доступношћу мреже или стањем спољних сервиса.
Одржавајте независност тестова: сваки интеграциони тест мора радити изоловано, без зависности од резултата других тестова. Користите @Before и @After анотације у JUnit-у или setUp и tearDown у XCTest-у за припрему и чишћење тест окружења. То спречава међусобни утицај тестова и поједностављује дијагностику грешака.
Покријте граничне случајеве: интеграциони тестови треба да проверавају не само успешне сценарије (happy path), већ и обраду грешака — тајмауте, HTTP кодове 4xx и 5xx, празне одговоре, оштећени JSON. Према подацима Google Testing Blog (2022), 60% производних инцидената повезано је са некоректном обрадом граничних случајева који нису били покривени тестовима.
Често постављана питања
Јединични тестови проверавају једну класу или функцију у изолацији, замењујући зависности заглушкама. Интеграциони тестови проверавају интеракцију неколико стварних компонената — на пример, мрежну везу и базу података истовремено.
Покретање интеграционих тестова обично траје од 2 до 15 минута у зависности од броја тестова и сложености окружења. За велике пројекте препоручује се подела тестова на паралелне џобове у CI систему како би се скратило укупно време провере пре спајања.
У првом реду, интеграциони тестови се пишу за мрежни слој, базу података и системске сервисе — обавештења, камеру, геолокацију. API захтеви ка бекенду и операције са локалним складиштем дају највећи ROI, јер ове компоненте најчешће постају извори регресија.
За један екран довољни су јединични тестови ViewModel-а и UI тестови. Интеграциони тестови за један екран су оправдани само ако екран интерагује са више извора података — на пример, комбинује одговоре са два различита API-ја или уписује податке истовремено у мрежу и локалну базу.
Интеграциони тестови се покрећу при сваком pull request-у у CI пајплајну и пре главних објављивања. Такође се препоручује покретање пуног скупа интеграционих тестова ноћу (nightly build) како би се открили дефекти повезани са променама у зависностима или тест окружењу.
Закључци
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође