XCTest: nyckelbegrepp, XCTestCase-klasser och att skriva tester

Författare: IT Sectr Publicerad: 2026-04-08 Lästid: 11 min

XCTest — är Apples ramverk för modulär och integrationstestning av applikationer för iOS, macOS, watchOS och tvOS. XCTest ingår i Xcode och stöder att skriva tester i Swift och Objective-C. Till skillnad från externa ramverk (Quick, Nimble) är XCTest Apples officiella lösning och är helt integrerad med Xcode Server och CI/CD. Enligt Apple Developer (2024) används XCTest i 94% av iOS-apparna från topp-100 App Store. XCTest ger en stabil grund för att skriva unit-tester och UI-tester utan externa beroenden.

Huvudpunkter

  • XCTest — Apples officiella ramverk för unit-testning och UI-testning i Swift och Objective-C.
  • XCTestCase — basklassen för alla tester som tillhandahåller setUp, tearDown och assert-metoder.
  • Asserts — XCTAssertTrue, XCTAssertEqual, XCTAssertNil och andra för att kontrollera förväntade resultat.
  • XCTestExpectation — mekanism för att testa asynkron kod med förväntan om utförande.
  • Prestandatester — mätning av kodens exekveringstid via metoden measure(metrics:) med tröskelvärden.

Vad är XCTest?

XCTest — är ett ramverk för modulär, integrations- och UI-testning, utvecklat av Apple och inbyggt i Xcode sedan version 5.0 (2013). XCTest ersatte OCUnit (SenTestingKit) och tillhandahöll ett modernt API i Swift med stöd för asynkrona tester, prestandatester och integration med Xcode Server. Enligt Swift.org (2024) är XCTest grunden för testning i alla Apple-projekt, inklusive Swift Package Manager, som använder XCTest för självtestning.

XCTest arbetar tillsammans med Xcode Test Navigator och Report Navigator, som visar testträdet, exekveringshistorik och jämför resultat mellan byggen. Test Navigator gör det möjligt att köra ett enskilt test, en grupp tester eller hela sviten utan att ändra kod. Resultaten visas som gröna (passed), röda (failed) och gula (skipped) ikoner. Enligt Apple WWDC (2024) förbättrade Xcode 16 parallelltestkörning med 40% genom att använda flera simulatorer.

XCTest stöder plattformar: iOS 8.0+, macOS 10.10+, watchOS 2.0+, tvOS 9.0+. För varje plattform finns samma API tillgängligt, vilket möjliggör skrivning av cross-platform-tester. Swift Testing — ett nytt Apple-ramverk (tillkännagivet 2024) som i framtiden kommer att komplettera XCTest, men inte helt ersätta det. XCTest förblir det huvudsakliga ramverket för testning i Apples ekosystem.

XCTestCase — basklassen för tester

XCTestCase — är basklassen från vilken alla testklasser i XCTest ärver. Den tillhandahåller testets livscykel: `setUp()` anropas före varje test, `tearDown()` — efter varje test. SetUp används för initiering av objekt och mockar, tearDown — för rensning av resurser. setUpWithError och tearDownWithError möjliggör hantering av initieringsfel utan try-catch i varje test.

Varje metod vars namn börjar med `test` identifieras automatiskt av Xcode som ett test. Alternativt kan makrot `@Test` (Swift Testing) användas. Testnamnet bör vara beskrivande: `testLoginWithValidCredentials` är bättre än `testLogin1`. Dokumentation av tester via kommentarer är god praxis, men Xcode tillåter att lägga till beskrivning via User-Defined Attributes.

swift
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")
    }
}

Exemplet ovan visar standardstrukturen för XCTestCase. sut (System Under Test) — namnkonvention för det testade objektet. MockURLSession ersätter det verkliga nätverket och möjliggör testning av UserService isolerat. Principen "ett test — en kontroll" förenklar felsökning. Varje XCTestCase-test bör kontrollera ett scenario eller ett påstående.

Asserts i XCTest

Grundläggande grupp av asserts

XCTAssertTrue och XCTAssertFalse — grundläggande asserts för att kontrollera booleska värden. XCTAssertTrue(expression) godkänns om expression == true. XCTAssertEqual kontrollerar likheten mellan två värden med stöd för alla typer som implementerar Equatable. För flyttal används XCTAssertEqual med parametern accuracy för att ta hänsyn till beräkningsfel. Enligt Google Testing Blog (2024) täcker XCTAssertEqual 70% av alla kontroller i en typisk testsvit.

Nil-asserts och fel

XCTAssertNil och XCTAssertNotNil kontrollerar optionella värden för nil. Dessa asserts är kritiska för Swift, där optionella typer används i stor utsträckning. XCTAssertThrowsError kontrollerar om koden kastar ett förväntat fel. XCTUnwrap — en assert som extraherar ett optionellt värde och misslyckas med ett tydligt meddelande om värdet är nil. Jämförelse av strängar via XCTAssertEqual använder bokstavlig jämförelse, inte semantisk. XCTAssertNoThrow — motsvarande assert för att kontrollera att koden inte kastar ett fel.

AssertSyfteExempel
XCTAssertEqualKontrollera likhetXCTAssertEqual(a, b)
XCTAssertTrueKontrollera sanningXCTAssertTrue(result)
XCTAssertNilKontrollera nilXCTAssertNil(error)
XCTAssertThrowsErrorKontrollera felXCTAssertThrowsError(try parse(""))
XCTUnwrapExtrahera optionalXCTUnwrap(value)

XCTestExpectation och asynkrona tester

XCTestExpectation — är en mekanism för att testa asynkron kod. Testet skapar en förväntan med ett beskrivande namn, skickar den till den asynkrona operationen och anropar `wait(for:timeout:)`. Om förväntan inte uppfylls inom tidsgränsen misslyckas testet. Tidsgräns är som standard 10 sekunder, men för snabba operationer rekommenderas 1–3 sekunder för att påskynda den totala testtiden.

XCTWaiter — ett mer flexibelt alternativ till wait(for:timeout:). XCTWaiter gör det möjligt att vänta på flera förväntningar, konfigurera exekveringsordning och hantera tidsgränser programmatiskt. Till skillnad från wait returnerar XCTWaiter `XCTWaiter.Result`, som kan analyseras. Delegat XCTWaiterDelegate meddelar om överträdelse av förväntansordning och tidsgränser.

swift
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")
}

I exemplet används XCTestExpectation för att testa asynkron inloggning. fulfill() anropas inuti callbacken och signalerar att den asynkrona operationen är slutförd. Om fulfill() inte anropas inom 3 sekunder — misslyckas testet med timeout. Efter framgångsrik väntan utförs asserts för att kontrollera resultatet. Flera förväntningar kan skickas som en array och vänta på att alla uppfylls.

Prestandatester med XCTest

measure(metrics:) — XCTestCase-metoden för att skapa prestandatester. Kodblocket inuti measure körs 10 gånger i rad och XCTest samlar statistik: genomsnittlig tid, median, standardavvikelse. Metrics — arrayen av spårade mätvärden: XCTClockMetric (tid), XCTMemoryMetric (minne), XCTStorageMetric (disk) och XCTCPUMetric (processor). Enligt Apple WWDC (2024) är prestandatester med XCTCPUMetric användbara för att upptäcka regressioner i algoritmer.

Baseline (baslinje) för prestandatester ställs in i Xcode Test Plan. Om exekveringstiden överskrider baslinjen med en fastställd procentsats (standard 10%) anses testet misslyckat. Baslinjen uppdateras manuellt efter bekräftelse av att prestandaförändringen är förväntad. Test Plan i Xcode gör det möjligt att gruppera prestandatester efter konfiguration: debug/release, olika enheter, olika iOS-versioner.

swift
func testArraySortPerformance() {
    let numbers = (1...10000).shuffled()
    measure(metrics: [XCTClockMetric()]) {
        let _ = numbers.sorted()
    }
}

Detta prestandatest mäter sorteringstiden för en array med 10000 element. XCTClockMetric registrerar den faktiska exekveringstiden. Om tiden efter ändring av sorteringsalgoritmen ökar med 10% eller mer kommer testet att indikera regression. XCTest-prestandatester är särskilt användbara för: databehandlingsalgoritmer, rendering av UI-komponenter, databasoperationer och nätverksförfrågningar.

Organisering av tester och CI/CD-integration

Struktur för testprojekt

Strukturen för testprojektet i XCTest följer konventionen: en testfil per klass, placerad i en separat `<TargetName>Tests`-katalog. Filnamnen motsvarar namnen på de testade klasserna med suffixet `Tests`: `UserService.swift` → `UserServiceTests.swift`. Test Targets i Xcode konfigureras separat för unit-tester och UI-tester, vilket möjliggör oberoende körning. Schemes i Xcode hanterar byggkonfigurationen och uppsättningen tester som körs.

CI/CD-integration

Xcode Cloud och GitHub Actions stöder körning av XCTest via `xcodebuild test -scheme App -testPlan SmokeTest`. CI-pipelinen inkluderar: bygg → kör unit-tester → kör UI-tester → publicera rapport. JUnit-rapporten genereras av `xcodebuild` med alternativet `-resultBundlePath` och kan importeras till vilket CI-verktyg som helst. Code Coverage — inbyggd funktion i XCTest som visar vilka kodrader som täcks av tester. Minsta täckningströskel för produktionskod — 70% för kritisk affärslogik.

Xcode Cloud och GitHub Actions stöder körning av XCTest via `xcodebuild test -scheme App -testPlan SmokeTest`. CI-pipelinen inkluderar: bygg → kör unit-tester → kör UI-tester → publicera rapport. JUnit-rapport genereras av `xcodebuild` med alternativet `-resultBundlePath` och kan importeras till vilket CI-verktyg som helst. Bitrise och Jenkins har färdiga steg för XCTest.

Code Coverage — inbyggd funktion i XCTest som visar vilka kodrader som täcks av tester. Xcode visar täckning i grönt (täckt), rött (inte täckt) och gult (delvis täckt). Minsta tröskel för produktionskod — 70% för kritisk affärslogik. Enligt Google Testing Blog (2024) leder tvångskrav på 80% täckning för alla moduler till uppkomsten av "tomma tester" som inte kontrollerar logik, bara exekverar kod.

Vanliga frågor

Hur skiljer sig XCTest från Quick och Nimble?

XCTest — Apples officiella ramverk med direkt integration i Xcode. Quick och Nimble — tredjepartsbibliotek som tillhandahåller BDD-syntax och mer läsbara asserts. Quick och Nimble är bekväma för Acceptance Testing, men XCTest är mer pålitligt för unit-tester på grund av avsaknaden av externa beroenden.

Hur testar man asynkron kod i XCTest?

Asynkron kod testas via XCTestExpectation + `wait(for:timeout:)` eller via `async/await`-metoder i XCTest (iOS 13+). För callback-baserade API:er skapas en förväntan som anropas i closure. För async/await används standard asserts i async-funktioner.

Hur mockar man beroenden i XCTest?

XCTest innehåller inget inbyggt ramverk för mockar. Mockning realiseras via protokoll: en mock-klass skapas som implementerar samma protokoll som det verkliga beroendet. För automatisk generering av mockar används Cuckoo, SwiftyMocky eller manuella mockar. Dependency Injection via initierare — obligatoriskt villkor för testning.

Kan XCTest köras på riktiga enheter?

Ja, XCTest körs på riktiga enheter via Xcode eller xcodebuild med parametern `-destination 'platform=iOS,name=iPhone 15'`. UI-tester på riktiga enheter ger mer exakta resultat än på simulatorer. För körning på enhetsfarmar används BrowserStack, Sauce Labs eller Firebase Test Lab.

Vad är nytt i Swift Testing jämfört med XCTest?

Swift Testing (2024) — ett nytt Apple-ramverk med makron `@Test`, `@Suite` och `@Expect`. Det erbjuder inbyggd parametrisering av tester, gruppering i sviter och mer läsbar syntax. Swift Testing samexisterar med XCTest och ersätter det inte. XCTest förblir det huvudsakliga ramverket för UI-tester och prestandatester.

Sammanfattning

  • XCTest — Apples officiella testramverk, inbyggt i Xcode och stöder Swift och Objective-C.
  • XCTestCase tillhandahåller livscykeln setUp/tearDown och en uppsättning asserts för unit-tester.
  • XCTestExpectation och XCTWaiter — mekanismer för att testa asynkron kod med callback och async/await.
  • Prestandatester använder measure(metrics:) med stöd för XCTClockMetric, XCTMemoryMetric och XCTCPUMetric.
  • Asserts — XCTAssertEqual, XCTAssertTrue, XCTAssertNil, XCTAssertThrowsError, XCTUnwrap och andra.
  • CI/CD-integration via xcodebuild, Xcode Cloud och GitHub Actions med automatisk rapportgenerering.
  • Swift Testing — ett nytt Apple-ramverk som kompletterar XCTest för unit-tester och parametrisering.

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också