XCTest — je framework Apple pro modulární a integrační testování aplikací pro iOS, macOS, watchOS a tvOS. XCTest je součástí Xcode a podporuje psaní testů ve Swift a Objective-C. Na rozdíl od externích frameworků (Quick, Nimble) je XCTest oficiálním řešením Apple a je plně integrován s Xcode Server a CI/CD. Podle Apple Developer (2024) se XCTest používá v 94% iOS aplikací z top-100 App Store. XCTest poskytuje stabilní základ pro psaní unit-testů a UI-testů bez externích závislostí.
Hlavní body
XCTest — je framework pro modulární, integrační a UI testování, vyvinutý společností Apple a integrovaný do Xcode od verze 5.0 (2013). XCTest nahradil OCUnit (SenTestingKit) a poskytl moderní API ve Swift s podporou asynchronních testů, výkonnostních testů a integrace s Xcode Server. Podle Swift.org (2024) je XCTest základem testování ve všech projektech Apple, včetně Swift Package Manager, který používá XCTest pro sebetestování.
XCTest pracuje ve spojení s Xcode Test Navigator a Report Navigator, které zobrazují strom testů, historii provádění a porovnávají výsledky mezi sestaveními. Test Navigator umožňuje spuštění jednoho testu, skupiny testů nebo celé sady bez změny kódu. Výsledky se zobrazují jako zelené (passed), červené (failed) a žluté (skipped) ikony. Podle Apple WWDC (2024) Xcode 16 zlepšil paralelní spouštění testů o 40% pomocí více simulátorů.
XCTest podporuje platformy: iOS 8.0+, macOS 10.10+, watchOS 2.0+, tvOS 9.0+. Pro každou platformu je k dispozici stejné API, což umožňuje psaní cross-platform testů. Swift Testing — nový framework Apple (oznámen v roce 2024), který v budoucnu doplní XCTest, ale zcela jej nenahradí. XCTest zůstává hlavním frameworkem pro testování v ekosystému Apple.
XCTestCase — je základní třída, od které dědí všechny testovací třídy v XCTest. Poskytuje životní cyklus testu: `setUp()` se volá před každým testem, `tearDown()` — po každém testu. SetUp se používá pro inicializaci objektů a mocků, tearDown — pro čištění zdrojů. setUpWithError a tearDownWithError umožňují zpracování chyb inicializace bez try-catch v každém testu.
Každá metoda, jejíž název začíná na `test`, je automaticky rozpoznána Xcode jako test. Alternativně lze použít makro `@Test` (Swift Testing). Název testu by měl být popisný: `testLoginWithValidCredentials` je lepší než `testLogin1`. Dokumentování testů pomocí komentářů je dobrá praxe, ale Xcode umožňuje přidání popisu pomocí User-Defined Attributes.
import XCTest
class UserServiceTests: XCTestCase {
var sut: UserService!
var mockSession: MockURLSession!
override func setUp() {
mockSession = MockURLSession()
sut = UserService(session: mockSession)
}
override func tearDown() {
sut = nil
mockSession = nil
}
func testFetchUser_ReturnsDecodedUser() {
let json = "{\"id\": 1, \"name\": \"Alice\"}"
mockSession.setResponse(json)
let user = try await sut.fetchUser(id: 1)
XCTAssertEqual(user.name, "Alice")
}
}
Výše uvedený příklad ukazuje standardní strukturu XCTestCase. sut (System Under Test) — konvence pojmenování testovaného objektu. MockURLSession nahrazuje skutečnou síť a umožňuje testování UserService v izolaci. Princip "jeden test — jedna kontrola" zjednodušuje ladění. Každý XCTestCase test by měl kontrolovat jeden scénář nebo jedno tvrzení.
XCTAssertTrue a XCTAssertFalse — základní aserce pro kontrolu booleovských hodnot. XCTAssertTrue(expression) projde, pokud expression == true. XCTAssertEqual kontroluje rovnost dvou hodnot s podporou všech typů implementujících Equatable. Pro čísla s plovoucí čárkou se používá XCTAssertEqual s parametrem accuracy pro zohlednění chyby výpočtu. Podle Google Testing Blog (2024) pokrývá XCTAssertEqual 70% všech kontrol v typické testovací sadě.
XCTAssertNil a XCTAssertNotNil kontrolují volitelné hodnoty na nil. Tyto aserce jsou kritické pro Swift, kde jsou volitelné typy široce používány. XCTAssertThrowsError kontroluje, zda kód vyvolává očekávanou chybu. XCTUnwrap — aserce, která extrahuje volitelnou hodnotu a selže se srozumitelnou zprávou, pokud je hodnota nil. Porovnání řetězců pomocí XCTAssertEqual používá doslovné porovnání, nikoli sémantické. XCTAssertNoThrow — párová aserce pro kontrolu, že kód nevyvolává chybu.
| Aserce | Účel | Příklad |
|---|---|---|
| XCTAssertEqual | Kontrola rovnosti | XCTAssertEqual(a, b) |
| XCTAssertTrue | Kontrola pravdivosti | XCTAssertTrue(result) |
| XCTAssertNil | Kontrola nil | XCTAssertNil(error) |
| XCTAssertThrowsError | Kontrola chyby | XCTAssertThrowsError(try parse("")) |
| XCTUnwrap | Extrakce optional | XCTUnwrap(value) |
XCTestExpectation — je mechanismus pro testování asynchronního kódu. Test vytvoří očekávání s popisným názvem, předá ho asynchronní operaci a zavolá `wait(for:timeout:)`. Pokud očekávání není splněno v časovém limitu, test selže. Časový limit je ve výchozím nastavení 10 sekund, ale pro rychlé operace se doporučuje nastavit 1–3 sekundy pro urychlení celkového času testování.
XCTWaiter — flexibilnější alternativa k wait(for:timeout:). XCTWaiter umožňuje čekání na více očekávání, konfiguraci pořadí provádění a programové zpracování časových limitů. Na rozdíl od wait vrací XCTWaiter `XCTWaiter.Result`, který lze analyzovat. Delegát XCTWaiterDelegate informuje o porušení pořadí očekávání a časových limitech.
func testAsyncLogin() {
let expectation = XCTestExpectation(description: "login")
var resultUser: User?
sut.login(email: "a@b.com", password: "123") { user in
resultUser = user
expectation.fulfill()
}
wait(for: [expectation], timeout: 3)
XCTAssertNotNil(resultUser)
XCTAssertEqual(resultUser?.email, "a@b.com")
}
V příkladu se XCTestExpectation používá pro testování asynchronního přihlášení. fulfill() je voláno uvnitř callbacku a signalizuje, že asynchronní operace byla dokončena. Pokud do 3 sekund není fulfill() voláno — test selže s timeoutem. Po úspěšném čekání se provedou aserce pro kontrolu výsledku. Více očekávání lze předat jako pole a čekat na splnění všech.
measure(metrics:) — metoda XCTestCase pro vytváření výkonnostních testů. Blok kódu uvnitř measure se spouští 10krát za sebou a XCTest shromažďuje statistiky: průměrný čas, medián, směrodatnou odchylku. Metrics — pole sledovaných metrik: XCTClockMetric (čas), XCTMemoryMetric (paměť), XCTStorageMetric (disk) a XCTCPUMetric (procesor). Podle Apple WWDC (2024) jsou výkonnostní testy s XCTCPUMetric užitečné pro detekci regresí v algoritmech.
Baseline (základní linie) pro výkonnostní testy se nastavuje v Xcode Test Plan. Pokud doba provedení překročí baseline o stanovené procento (výchozí 10%), test je považován za neúspěšný. Baseline se aktualizuje ručně po potvrzení, že změna výkonu je očekávaná. Test Plan v Xcode umožňuje seskupování výkonnostních testů podle konfigurací: debug/release, různá zařízení, různé verze iOS.
func testArraySortPerformance() {
let numbers = (1...10000).shuffled()
measure(metrics: [XCTClockMetric()]) {
let _ = numbers.sorted()
}
}
Tento výkonnostní test měří čas řazení pole 10000 prvků. XCTClockMetric zaznamenává skutečný čas provedení. Pokud se po změně řadicího algoritmu čas zvýší o 10% nebo více, test ukáže regresi. Výkonnostní testy XCTest jsou zvláště užitečné pro: algoritmy zpracování dat, vykreslování UI komponent, databázové operace a síťové požadavky.
Struktura testovacího projektu v XCTest následuje konvenci: jeden testovací soubor na třídu, umístěný v samostatném adresáři `<TargetName>Tests`. Názvy souborů odpovídají názvům testovaných tříd s příponou `Tests`: `UserService.swift` → `UserServiceTests.swift`. Test Targets v Xcode jsou konfigurovány samostatně pro unit-testy a UI-testy, což umožňuje jejich nezávislé spouštění. Schemes v Xcode spravují konfiguraci sestavení a sadu spouštěných testů.
Xcode Cloud a GitHub Actions podporují spouštění XCTest pomocí `xcodebuild test -scheme App -testPlan SmokeTest`. CI pipeline zahrnuje: sestavení → spuštění unit-testů → spuštění UI-testů → publikování zprávy. JUnit zpráva je generována `xcodebuild` s možností `-resultBundlePath` a může být importována do jakéhokoli CI nástroje. Code Coverage — vestavěná funkce XCTest, která ukazuje, které řádky kódu jsou pokryty testy. Minimální práh pokrytí pro produkční kód — 70% pro kritickou obchodní logiku.
Xcode Cloud a GitHub Actions podporují spouštění XCTest pomocí `xcodebuild test -scheme App -testPlan SmokeTest`. CI pipeline zahrnuje: sestavení → spuštění unit-testů → spuštění UI-testů → publikování zprávy. JUnit zpráva je generována `xcodebuild` s možností `-resultBundlePath` a může být importována do jakéhokoli CI nástroje. Bitrise a Jenkins mají připravené kroky pro XCTest.
Code Coverage — vestavěná funkce XCTest, která ukazuje, které řádky kódu jsou pokryty testy. Xcode zobrazuje pokrytí zeleně (pokryto), červeně (nepokryto) a žlutě (částečně pokryto). Minimální práh pokrytí pro produkční kód — 70% pro kritickou obchodní logiku. Podle Google Testing Blog (2024) vynucování 80% pokrytí pro všechny moduly vede ke vzniku "prázdných testů", které nekontrolují logiku, pouze provádějí kód.
Často kladené otázky
XCTest — oficiální framework Apple s přímou integrací v Xcode. Quick a Nimble — knihovny třetích stran, které poskytují BDD syntaxi a čitelnější aserce. Quick a Nimble jsou vhodné pro Acceptance Testing, ale XCTest je spolehlivější pro unit-testy kvůli absenci externích závislostí.
Asynchronní kód se testuje pomocí XCTestExpectation + `wait(for:timeout:)` nebo pomocí `async/await` metod XCTest (iOS 13+). Pro callback-based API se vytvoří očekávání, které se volá v uzavření. Pro async/await se používají standardní aserce v async funkcích.
XCTest neobsahuje vestavěný framework pro mocky. Mockování se realizuje pomocí protokolů: vytvoří se mock třída, která implementuje stejný protokol jako skutečná závislost. Pro automatické generování mocků se používají Cuckoo, SwiftyMocky nebo ruční mocky. Dependency Injection přes inicializátory — povinná podmínka pro testování.
Ano, XCTest se spouští na skutečných zařízeních přes Xcode nebo xcodebuild s parametrem `-destination 'platform=iOS,name=iPhone 15'`. UI-testy na skutečných zařízeních poskytují přesnější výsledky než na simulátorech. Pro spouštění na farmách zařízení se používají BrowserStack, Sauce Labs nebo Firebase Test Lab.
Swift Testing (2024) — nový framework Apple s makry `@Test`, `@Suite` a `@Expect`. Poskytuje vestavěnou parametrizaci testů, seskupování do sad a čitelnější syntaxi. Swift Testing koexistuje s XCTest a nenahrazuje jej. XCTest zůstává hlavním frameworkem pro UI-testy a výkonnostní testy.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také