Egységtesztelés a mobilfejlesztésben: mi ez, módszerek és keretrendszerek

Szerző: IT Sectr Megjelenés: 2026-04-06 Olvasási idő: 9 perc

Az egységtesztelés a szoftverellenőrzés egy olyan módszere, amelynél az egyes modulok vagy kódfüggvények helyes működését a rendszer többi részétől elkülönítve tesztelik. A Martin Fowler, 2026 adatai szerint a modultesztek a CI/CD és a refaktorálás alapját képezik, gyors visszajelzést biztosítva a kód működőképességéről. A modultesztelés segít a hibák korai felismerésében a fejlesztés során, tízszeresére csökkentve a javítási költségeket.

Fontos tudnivalók

  • Egységteszt — egy modul (függvény, metódus, osztály) ellenőrzése külső függőségektől elkülönítve
  • FIRST elvek — Fast, Isolated, Repeatable, Self-validating, Timely — a minőségi tesztek alapja
  • Mockok és stábok — a külső függőségek (adatbázis, API, fájlrendszer) helyettesítői, biztosítva a teszt elkülönítését
  • TDD (Test-Driven Development) — tesztvezérelt fejlesztési módszertan: piros-zöld-refaktor
  • Tesztpiramis — az egységtesztek a piramis 70%-át teszik ki, gyors visszajelzést biztosítva minden commitnál

Mi az egységtesztelés?

Az egységtesztelés a forráskód egyes egységeinek (unit) — függvények, metódusok, osztályok — ellenőrzésének folyamata a program többi részétől elkülönítve. Minden teszt egy adott modulhasználati forgatókönyvet futtat le, és ellenőrzi, hogy az eredmény megfelel-e a vártnak. Az egységtesztek ugyanazon a programozási nyelven íródnak, mint az alapkód, és automatikusan futnak a fejlesztői környezetben vagy a CI/CD pipeline-ban. Az integrációs tesztekkel ellentétben a modultesztek nem lépnek interakcióba valós adatbázisokkal, fájlrendszerrel vagy hálózati szolgáltatásokkal.

Miért van szükség egységtesztekre?

A fő cél a gyors visszacsatolás a kód helyességéről a változtatások után. Ha egy fejlesztő refaktorál egy metódust, az egységtesztek halmaza megerősíti, hogy a viselkedés nem tört el. A Google Testing Blog (2025) adatai szerint a 60% feletti modultesztekkel rendelkező projektekben 2,5-szer kevesebb production-incidens fordul elő. További előnyök: kód dokumentáció (a tesztek megmutatják, hogyan kell használni az API-t), a refaktorálás egyszerűsítése (a megvalósítás változtatható a viselkedés megőrzése mellett) és a regressziók gyors diagnosztizálása.

Mi számít egységtesztnek?

Nem minden automatikus teszt egységteszt. Kritériumok: egy modult (osztály vagy függvény) tesztelünk, a külső függőségeket mockokkal vagy stábokkal helyettesítjük, a teszt ezredmásodpercek alatt fut, nem igényel szerver vagy adatbázis elindítását. Az a teszt, amely valós adatbázishoz fordul — integrációs teszt. Az a teszt, amely böngészőt nyit — E2E-teszt. A teszttípusok közötti határok megértése fontos a tevékenységek helyes elosztásához a tesztpiramisban.

A FIRST elvek és az AAA struktúra

A minőségi egységtesztek a Robert C. Martin által megfogalmazott FIRST elveket követik. Minden tesztnek Fast (gyors — ezredmásodpercek), Isolated (elkülönített — nem függ más tesztektől), Repeatable (ismételhető — azonos eredmény bármely gépen), Self-validating (önellenőrző — az eredmény „passed" vagy „failed", kézi ellenőrzés nélkül) és Timely (időszerű — a kód előtt vagy azzal egy időben íródott) kell lennie. Bármely elv megsértése csökkenti a teszt értékét.

AAA struktúra (Arrange-Act-Assert)

Az egységtesztek írásának szabványos mintája. Arrange — az adatok és függőségek előkészítése: objektumok létrehozása, mockok beállítása, bemeneti paraméterek megadása. Act — a tesztelendő művelet végrehajtása: metódus vagy függvény meghívása. Assert — az eredmény ellenőrzése: a tényleges érték összehasonlítása a várt értékkel. A három blokkra bontás olvashatóvá és érthetővé teszi a tesztet. Ha az Assert blokk összetett logikát igényel, a teszt valószínűleg túl sokat ellenőriz egyszerre.

kotlin
// Példa egységtesztre AAA minta szerint Kotlinban JUnit 5-tel
class CalculatorTest {

    private lateinit var calculator: Calculator

    @BeforeEach
    fun setUp() {
        // ARRANGE — létrehozzuk a tesztelendő objektumot
        calculator = Calculator()
    }

    @Test
    fun addition_shouldReturnCorrectSum() {
        // ACT — végrehajtjuk a műveletet
        val result = calculator.add(2, 3)

        // ASSERT — ellenőrizzük az eredményt
        Assertions.assertEquals(5, result)
    }
}

Tesztek elnevezése

A teszt nevének le kell írnia, hogy mit ellenőriz és milyen eredmény várható. Formátum: [methodName]_[scenario]_[expectedResult]. Példa: calculateTotal_whenDiscountApplied_shouldReturnDiscountedTotal. Egy jó tesztnév helyettesíti a megjegyzést, és hiba esetén azonnal jelzi, hogy melyik funkcionalitás sérült. Kerülje az olyan neveket, mint test1, checkSomething vagy verify — ezek nem hordoznak információt és megnehezítik a diagnosztizálást.

Mockok, stábok és fékek: mit és mikor használjunk

A tesztelendő modul külső függőségektől való elkülönítéséhez tesztduplánsokat (test doubles) használunk. Fő típusok: mockok (mocks) — ellenőrzik, hogy egy adott metódust a megfelelő paraméterekkel hívtak-e meg; stábok (stubs) — előre meghatározott értékeket adnak vissza a metódus meghívásakor; fékek (fakes) — egy valós komponens egyszerűsített megvalósítása (például InMemoryUserRepository a UserRepository helyett, amely adatbázissal dolgozik). A választás attól függ, hogy mit kell ellenőrizni: állapotot (stáb) vagy interakciót (mock).

DuplánsMit ellenőrizPélda
MockMetódushívás helyes paraméterekkeluserRepository.save(user) pontosan 1-szer lett meghívva
StábVisszaadott értékrepository.findById(1) visszaadja a User(id=1, name=„Teszt") értéket
FékLogika egyszerűsített megvalósításon keresztülInMemoryMapUserRepository HashMap-mel adatbázis helyett
SpyValós objektum részleges mockolásaspy(repo).when(findById).thenReturn(user)

Mockito: példa mockolásra Java/Kotlin nyelven

A Mockito a legnépszerűbb mockoló keretrendszer Java és Kotlin nyelven. Lehetővé teszi mockok létrehozását a mock() segítségével, visszatérési értékek beállítását a when().thenReturn()-on keresztül, és hívások ellenőrzését a verify()-val. A Mockito modern verziói (5.x) támogatják a statikus mockolást (mockStatic) és az egyszerűsített szintaxist a BDDMockito-n keresztül (given-willReturn). Fontos szabály: ne mockoljon olyasmit, ami nem az Öné — ne hozzon létre mockokat értékobjektumokhoz és szabványos könyvtárakhoz.

kotlin
// Példa egységtesztre Mockito-val Kotlinban
class OrderServiceTest {

    @Mock
    private lateinit var paymentGateway: PaymentGateway

    @Mock
    private lateinit var userRepository: UserRepository

    private lateinit var orderService: OrderService

    @BeforeEach
    fun init() {
        MockitoAnnotations.openMocks(this)
        orderService = OrderService(paymentGateway, userRepository)
    }

    @Test
    fun processOrder_whenPaymentFails_shouldThrowException() {
        // given
        val user = User(id = 1, balance = 100.0)
        val order = Order(amount = 200.0)
        Mockito.`when`(paymentGateway.charge(any())).thenReturn(false)
        Mockito.`when`(userRepository.findById(1)).thenReturn(user)

        // when & then
        assert Throws<PaymentException> {
            orderService.processOrder(user.id, order)
        }

        // verify
        Mockito.verify(paymentGateway).charge(any())
    }
}

TDD: tesztvezérelt fejlesztés

A TDD (Test-Driven Development) olyan módszertan, amelynél a tesztet a kód megvalósítása előtt írják meg. A „Piros-Zöld-Refaktor" ciklus: írjon egy tesztet, amely elbukik (Red), írja meg a minimális kódot a teszt átmenetéhez (Green), majd javítsa a kódot a viselkedés megváltoztatása nélkül (Refactor). A TDD garantálja, hogy a teljes kód lefedett tesztekkel (coverage = 100% az írott funkciókhoz), és hogy a kód tesztelhető — ha a kódot nehéz tesztelni, az azt jelenti, hogy az architektúra fejlesztésre szorul.

A TDD előnyei

Az IBM (2006-2026, longitudinális tanulmány) adatai szerint a TDD-t használó csapatok 40-80%-kal kevesebb hibát követnek el a production környezetben a teszteket utólag író csapatokhoz képest. A TDD javítja az architektúrát is: a fejlesztő kénytelen az API tervezésén gondolkodni a megvalósítás előtt, ami gyenge csatoláshoz (loose coupling) és magas kohézióhoz (high cohesion) vezet. További hatás: az élő kóddal történő dokumentáció — a tesztek a modul viselkedésének specifikációjaként szolgálnak, amely mindig naprakész.

Mikor nem megfelelő a TDD?

A TDD nem mindig optimális. A UI-komponenseket nehéz elkülönítve tesztelni — számukra hatékonyabbak a snapshot-tesztek vagy a vizuális regressziós tesztelés (Percy, Chromatic). A prototípuskészítés és kutatás (spike solutions) nem igényel teszteket. A tesztek nélküli örökölt kódot (legacy) nehéz TDD-vel lefedni — itt először jellemző tesztekre (characterization tests) van szükség, amelyek rögzítik az aktuális viselkedést a refaktorálás előtt. Ezekben az esetekben a TDD nem teljesen elvetendő, hanem alkalmazkodni kell — teszteket írunk a változtatandó funkciókra, nem a teljes örökölt kódra.

Egységtesztelés mobilalkalmazásokban

A mobilfejlesztésnek megvannak a sajátosságai: az üzleti logika gyakran keveredik a UI-kóddal (Activity, ViewController, ViewModel), ami megnehezíti az egységtesztelést. A legjobb gyakorlat a vékony View, vastag ViewModel: minden logikát vonjon ki a UI-összetevőkből külön osztályokba (UseCase, Repository, ViewModel), amelyek könnyen tesztelhetők emulátor nélkül. Android és iOS esetében léteznek natív egységtesztelési keretrendszerek, amelyek JVM/Native környezetben működnek az eszköz elindítása nélkül.

Egységtesztek Androidon (JUnit + Mockito/Robolectric)

Az Android egységtesztek a helyi JVM-en futnak emulátor nélkül, ami gyors végrehajtást biztosít — egy tipikus teszt kevesebb mint 100 ms-ot vesz igénybe. A JUnit 5 az alapvető futtatókeretrendszer. ViewModel-tesztekhez használja a kotlinx-coroutines-test-et a korutinok teszteléséhez és a Turbine-t a StateFlow teszteléséhez. A Robolectric lehetővé teszi az Android-függő komponensek (Context, Resources) tesztelését emulátor nélkül, shadow-osztályok betöltésével. Compose-tesztekhez használja a Compose UI Test-et — de ez már UI-teszt, nem egységteszt.

Egységtesztek iOS-en (XCTest + Quick/Nimble)

Az iOS egységtesztek Swift nyelven íródnak az XCTest segítségével (beépítve az Xcode-ba). A Quick + Nimble BDD-keretrendszerek az olvashatóbb tesztekhez (describe/context/it). Mockoláshoz használja a Cuckoo-t (mockgenerálás) vagy a SwiftyMocky-t. A Swift támogatja a protokollokat és a dependency injection-t, ami megkönnyíti a függőségek cseréjét. Fontos szempont: az iOS egységtesztek a macOS szimulátoron futnak, nem valós eszközön. A hardveres funkciókat (kamera, Bluetooth) igénylő tesztek integrációs tesztek.

Egységtesztek Flutterben (flutter_test + Mockito)

A Flutter egységtesztek a flutter_test csomagot használják, és a Dart VM-en futnak emulátor nélkül. Mockoláshoz a mockito csomagot kódgenerátorral (build_runner). A widget-tesztek (ugyanabban a csomagban) egyes widgeteket tesztelnek, de renderelést igényelnek és lassabbak — csak UI-logika ellenőrzéséhez használja őket. A tiszta Dart-logika (modellek, repozitóriumok, blokkok) szokásos Dart-tesztekként tesztelhető a flutter_test importálása nélkül.

dart
// Példa egységtesztre Flutterben mockito-val
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:mockito/annotations.dart';

@GenerateMocks([ApiClient])
import 'user_repository_test.mocks.dart';

void main() {
    late MockApiClient mockApi;
    late UserRepository repository;

    setUp(() {
        mockApi = MockApiClient();
        repository = UserRepository(mockApi);
    });

    test('fetchUser returns user when API succeeds', () async {
        // Előkészítés
        final expectedUser = User(id: 1, name: 'Test');
        when(mockApi.getUser(1))
            .thenAnswer((_) async => expectedUser);

        // Végrehajtás
        final result = await repository.fetchUser(1);

        // Ellenőrzés
        expect(result, expectedUser);
        verify(mockApi.getUser(1)).called(1);
    });
}

Legjobb gyakorlatok és tipikus hibák

A hatékony egységtesztelés fegyelmet igényel. A fő szabály: tesztelje a viselkedést, ne a megvalósítást. A tesztnek nem szabad tudnia, hogy a modul hogyan van belül megvalósítva (milyen privát metódusok hívódnak meg, milyen sorrendben). Ha a teszt a megvalósításhoz kötődik, minden refaktorálásnál eltörik, és elveszíti az értékét. A teszt a szerződést ellenőrzi: X bemenetre Y kimenetnek kell következnie. Kivételt képeznek a kritikus teljesítményű algoritmusok tesztjei, ahol a hívások sorrendje fontos.

  • Egy ellenőrzés tesztenként — egy assert vagy egy kapcsolódó assertek csoportja egy logikai ellenőrzéshez
  • Kerülje az ismétlést — használja a @BeforeEach / setUp-ot a közös inicializáláshoz, paraméterezett teszteket a különböző bemeneti adatokhoz
  • Ne tesztelje a privát metódusokat — tesztelje a nyilvános API-n keresztül. Ha egy privát metódus nincs lefedve, az azt jelenti, hogy a logikája kívülről nem látható
  • Fedje le a határeseteket — üres gyűjtemények, null/undefined, negatív számok, maximális értékek
  • Ne használjon Thread.sleep-et a tesztekben — ez lassúvá és instabillá teszi a teszteket. Használjon teszt-időtúllépéseket és korutinokat

Milyen coverage tekinthető elegendőnek?

A 100%-os coverage elérhetetlen és nem is szükséges cél. A Google Testing Blog (2025) adatai szerint az optimális lefedettségi szint az egységtesztekhez a kódsorok 70-80%-a. A 100%-os coverage gyakran getterek, setterek és konstruktorok tesztelésével érhető el, ami nem hoz értéket. Összpontosítson a kritikus üzleti logikára: összetett számítások, validáció, hibakezelés, határesetek. Használja a JaCoCo-t (Java), Coverage.py-t (Python), Istanbul-t (JS) a méréshez, és állítson be küszöbértéket a CI-ben — build megszakítás 60% alatti coverage esetén.

CI/CD és egységtesztek

Az egységtesztek bármely CI/CD pipeline első szakasza. Minden push-nál lefutnak a repozitóriumba, az építés és telepítés előtt. Az egységtesztek átlagos futási ideje egy projektben nem haladhatja meg az 5 percet — ha hosszabb, a tesztek megszűnnek „gyorsnak" lenni, és a fejlesztők nem futtatják őket lokálisan. Ossza szét a teszteket gyors (unit) és lassú (integration) kategóriákra, és futtassa őket a pipeline különböző szakaszaiban. Használjon párhuzamos végrehajtást és fail-fast-et a gyorsítás érdekében.

Gyakran ismételt kérdések

Miben különbözik az egységteszt az integrációs tesztől?

Az egységteszt egy modult ellenőriz elkülönítve, a külső függőségeket mockokkal helyettesítve. Az integrációs teszt több valós komponens (adatbázis, API, fájlrendszer) közötti interakciót ellenőrzi. Az egységtesztek ezredmásodpercek alatt futnak, az integrációs tesztek másodpercek alatt. A tesztpiramisban az egységtesztek 70%-ot tesznek ki.

Melyik keretrendszert válasszam az egységtesztekhez?

A választás a platformtól függ: JUnit 5 Java/Kotlin, XCTest iOS/Swift, pytest Python, Jest/Vitest JavaScript/TypeScript, flutter_test Flutter esetén. Mockoláshoz használja a Mockito-t (Java), Cuckoo-t (iOS), unittest.mock-ot (Python) vagy vitest.mock-ot (JS). Minden modern keretrendszer támogatja a paraméterezett teszteket, a beépített asserteket és a párhuzamos futtatást.

Mik a F.I.R.S.T. tesztelési elvek?

Fast — a teszt ezredmásodpercek alatt fut. Isolated — nem függ más tesztektől és külső rendszerektől. Repeatable — azonos eredményt ad bármely gépen. Self-validating — automatikusan ellenőrzi az eredményt. Timely — a kód előtt vagy azzal egy időben íródott. Bármely elv megsértése csökkenti a tesztelés hatékonyságát.

Kell egységteszteket írni a ViewModel-ekhez Android/iOS esetén?

Igen, mindenképpen. A ViewModel üzleti logikát tartalmaz — események feldolgozását, adatok transzformációját, állapotkezelést. Androidon használja a kotlinx-coroutines-test-et a korutinokhoz és a Turbine-t a StateFlow teszteléséhez. iOS-en tesztelje a Combine Publishers vagy async/await használatát a ViewModel-ben. A ViewModel-tesztek tiszta egységtesztek, amelyek a JVM/macOS környezetben futnak emulátor nélkül.

Hogyan teszteljünk hálózati kéréseket tartalmazó kódot?

A hálózati kérések egységtesztekben nem hajtódnak végre — helyette a HTTP-klienst mockolják. Androidon használja a MockWebServer-t (OkHttp) — ez egy helyi HTTP-szervert indít, ami előnyösebb a mockoknál, mert reprodukálja a valós hálózati interakciót. A MockWebServer elkülönítést biztosít a realizmus elvesztése nélkül. iOS-en használja az OHHTTPStubs vagy URLProtocol segítségét a válaszok elfogásához és helyettesítéséhez.

Összegzés

  • Egységtesztelés — egyes modulok ellenőrzése külső függőségektől elkülönítve, gyors visszajelzéssel
  • AAA struktúra — Arrange (előkészítés), Act (végrehajtás), Assert (ellenőrzés) — a teszt szabványos mintája
  • Mockok és stábok — tesztduplánsok az elkülönítéshez: a mockok a hívásokat ellenőrzik, a stábok értékeket adnak vissza
  • TDD — tesztvezérelt fejlesztés (Red-Green-Refactor) 40-80%-kal csökkenti a hibák számát
  • FIRST elvek — Fast, Isolated, Repeatable, Self-validating, Timely — a minőségi teszt alapja
  • Platform eszközök — JUnit 5 (Android), XCTest (iOS), flutter_test (Flutter), Jest (React Native)
  • 70-80%-os lefedettség — optimális szint a kritikus üzleti logikához, a getterek és setterek nem igényelnek teszteket

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is