XCTest — iOS, macOS, watchOS və tvOS üçün tətbiqlərin modul və inteqrasiya testi üçün Apple framework-üdür. XCTest Xcode-un tərkibinə daxildir və Swift və Objective-C dillərində testlərin yazılmasını dəstəkləyir. Kənar framework-lərdən (Quick, Nimble) fərqli olaraq, XCTest Apple-ın rəsmi həllidir və Xcode Server və CI/CD ilə tam inteqrasiya olunmuşdur. Apple Developer (2024) məlumatlarına görə, XCTest App Store-un top-100 iOS tətbiqinin 94%-də istifadə olunur. XCTest xarici asılılıqlar olmadan unit-testlər və UI-testlər yazmaq üçün sabit əsas təmin edir.
Əsas məqamlar
XCTest — Apple tərəfindən hazırlanmış və 5.0 versiyasından (2013-cü il) başlayaraq Xcode-a daxil edilmiş modul, inteqrasiya və UI testi framework-üdür. XCTest OCUnit (SenTestingKit) əvəz etdi və asinxron testlər, performance testləri və Xcode Server ilə inteqrasiya dəstəyi ilə Swift-də müasir API təmin etdi. Swift.org (2024) məlumatlarına görə, XCTest özünü yoxlama üçün XCTest-dən istifadə edən Swift Package Manager daxil olmaqla bütün Apple layihələrində test üçün əsasdır.
XCTest test ağacını, keçmə tarixçəsini göstərən və nəticələri qurmalar arasında müqayisə edən Xcode Test Navigator və Report Navigator ilə birlikdə işləyir. Test Navigator kodu dəyişmədən bir testi, test qrupunu və ya bütün dəsti işə salmağa imkan verir. Nəticələr yaşıl (passed), qırmızı (failed) və sarı (skipped) ikonlar kimi göstərilir. Apple WWDC (2024) məlumatlarına görə, Xcode 16 bir neçe simulyatordan istifadə etməklə paralel test işləməni 40% yaxşılaşdırdı.
XCTest platformaları dəstəkləyir: iOS 8.0+, macOS 10.10+, watchOS 2.0+, tvOS 9.0+. Hər bir platforma üçün eyni API mövcuddur ki, bu da platformalararası testlər yazmağa imkan verir. Swift Testing — gələcəkdə XCTest-i tamamlayacaq, lakin onu tamamilə əvəz etməyəcək yeni Apple framework-üdür (2024-cü ildə elan edilib). XCTest Apple ekosistemində test üçün əsas framework olaraq qalır.
XCTestCase — XCTest-də bütün test siniflərinin törədiyi əsas sinifdir. O, testin həyat dövriyyəsini təmin edir: `setUp()` hər testdən əvvəl çağrılır, `tearDown()` — hər testdən sonra. SetUp obyektlərin və mock-ların işə salınması üçün, tearDown resursların təmizlənməsi üçün istifadə olunur. setUpWithError və tearDownWithError hər testdə try-catch olmadan işə salma xətalarını idarə etməyə imkan verir.
Adı `test` ilə başlayan hər bir metod avtomatik olaraq Xcode tərəfindən test kimi tanınır. Alternativ olaraq `@Test` makrosundan (Swift Testing) istifadə etmək olar. Testin adı təsviri olmalıdır: `testLoginWithValidCredentials` `testLogin1`-dən yaxşıdır. Sənədləşdirmə testlərin şərhlər vasitəsilə aparılması yaxşı təcrübədir, lakin Xcode User-Defined Attributes vasitəsilə təsvir əlavə etməyə imkan verir.
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")
}
}
Yuxarıdakı nümunə XCTestCase-in standart strukturunu nümayiş etdirir. sut (System Under Test) — test edilən obyektin adlandırma konvensiyasıdır. MockURLSession real şəbəkəni əvəz edərək UserService-i təcrid olunmuş şəkildə test etməyə imkan verir. Əsas “bir test — bir yoxlama” prinsipi sazlamanı asanlaşdırır: test uğursuz olarsa, proqramçı dərhal hansı funksionallığın pozulduğunu bilir. Hər XCTestCase testi bir ssenari və ya bir təsdiqi yoxlamalıdır.
XCTAssertTrue və XCTAssertFalse — məntiqi dəyərləri yoxlamaq üçün əsas asersiyalardır. XCTAssertTrue(expression) expression == true olduqda keçir. XCTAssertEqual Equatable-ı tətbiq edən bütün tiplərin dəstəyi ilə iki dəyərin bərabərliyini yoxlayır. Kəsr ədədlər üçün hesablama xətasını nəzərə alan accuracy parametri ilə XCTAssertEqual istifadə olunur. Google Testing Blog (2024) məlumatlarına görə, XCTAssertEqual tipik test dəstində bütün yoxlamaların 70%-ni əhatə edir.
XCTAssertNil və XCTAssertNotNil isteğa bağlı dəyərləri nil üçün yoxlayır. Bu asersiyalar isteğa bağlı tiplərin geniş istifadə olunduğu Swift üçün kritik əhəmiyyət daşıyır. XCTAssertThrowsError kodun gözlənən xətanı atıb-atmadığını yoxlayır. XCTUnwrap — isteğa bağlı dəyəri çıxaran və dəyər nil olduqda başa düşülən mesajla uğursuz olan asersiyadır. XCTAssertEqual ilə sətirlərin müqayisəsi semantik deyil, hərfi müqayisədən istifadə edir. XCTAssertNoThrow — kodun xəta atmadığını yoxlamaq üçün qoşma asersiyadır.
| Asersiya | Təyinat | Nümunə |
|---|---|---|
| XCTAssertEqual | Bərabərliyin yoxlanması | XCTAssertEqual(a, b) |
| XCTAssertTrue | Doğruluğun yoxlanması | XCTAssertTrue(result) |
| XCTAssertNil | Nil-in yoxlanması | XCTAssertNil(error) |
| XCTAssertThrowsError | Xətanın yoxlanması | XCTAssertThrowsError(try parse("")) |
| XCTUnwrap | Optional-ın çıxarılması | XCTUnwrap(value) |
XCTestExpectation — asinxron kodun test edilməsi üçün mexanizmdir. Test təsviri adla gözlənti yaradır, onu asinxron əməliyyata ötürür və `wait(for:timeout:)` çağırır. Gözlənti vaxtında yerinə yetirilməzsə, test uğursuz olur. Vaxt limiti standart olaraq 10 saniyədir, lakin sürətli əməliyyatlar üçün ümumi test vaxtını sürətləndirmək üçün 1–3 saniyə təyin etmək tövsiyə olunur.
XCTWaiter — wait(for:timeout:) üçün daha çevik alternativdir. XCTWaiter bir neçe gözləntini gözləməyə, icra sırasını konfiqurasiya etməyə və vaxt limitlərini proqramlı idarə etməyə imkan verir. Wait-dən fərqli olaraq, XCTWaiter təhlil edilə bilən `XCTWaiter.Result` qaytarır. Delegat XCTWaiterDelegate gözlənti sırasının pozulması və vaxt keçməsi barədə xəbərdarlıq edir.
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")
}
Nümunədə XCTestExpectation asinxron girişin test edilməsi üçün istifadə olunur. fulfill() callback-in daxilində çağrılaraq asinxron əməliyyatın tamamlandığını bildirir. 3 saniyə ərzində fulfill() çağrılmazsa, test timeout ilə uğursuz olur. Uğurlu gözləmədən sonra nəticəni yoxlamaq üçün asersiyalar yerinə yetirilir. Bir neçe gözlənti massiv kimi ötürülə və hamısının yerinə yetirilməsi gözlənilə bilər.
measure(metrics:) — performance testləri yaratmaq üçün XCTestCase metodudur. Measure daxilindəki kod bloku ardıcıl olaraq 10 dəfə işə salınır və XCTest statistika toplayır: orta vaxt, median, standart sapma. Metrics — izlənilən ölçülər massividir: XCTClockMetric (vaxt), XCTMemoryMetric (yaddaş), XCTStorageMetric (disk) və XCTCPUMetric (prosessor). Apple WWDC (2024) məlumatlarına görə, XCTCPUMetric ilə performance testləri alqoritmlərdə reqressiyaları aşkarlamaq üçün faydalıdır.
Baseline (əsas xətt) performance testləri üçün Xcode Test Plan-da müəyyən edilir. İcra müddəti baseline-ı müəyyən edilmiş faizdən (şərti olaraq 10%) çox keçərsə, test uğursuz sayılır. Baseline performans dəyişikliyinin gözlənən olduğu təsdiqləndikdən sonra əl ilə yenilənir. Test Plan Xcode-da performance testlərini konfiqurasiyalar üzrə qruplaşdırmağa imkan verir: debug/release, müxtəlif cihazlar, müxtəlif iOS versiyaları.
func testArraySortPerformance() {
let numbers = (1...10000).shuffled()
measure(metrics: [XCTClockMetric()]) {
let _ = numbers.sorted()
}
}
Bu performance testi 10000 elementlik massivin çeşidlənmə vaxtını ölçür. XCTClockMetric real icra vaxtını qeyd edir. Çeşidlənmə alqoritmi dəyişdirildikdən sonra vaxt 10% və ya daha çox artarsa, test reqressiyanı göstərəcəkdir. XCTest performance testləri xüsusilə aşağıdakılar üçün faydalıdır: məlumat emalı alqoritmləri, UI komponentlərinin render edilməsi, verilənlər bazası əməliyyatları və şəbəkə sorğuları.
Test layihəsinin strukturu XCTest-də konvensiyaya uyğundur: bir sinif üçün bir test faylı, ayrı `<TargetName>Tests` direktoriyasında yerləşir. Fayl adları `Tests` şəkilçisi ilə test edilən siniflərin adlarına uyğun gəlir: `UserService.swift` → `UserServiceTests.swift`. Xcode-da Test Targets unit-testlər və UI-testlər üçün ayrıca konfiqurasiya edilir ki, bu da onların müstəqil işə salınmasına imkan verir. Schemes Xcode-da qurma konfiqurasiyasını və işə salınan testlər dəstini idarə edir.
Xcode Cloud və GitHub Actions `xcodebuild test -scheme App -testPlan SmokeTest` vasitəsilə XCTest-in işə salınmasını dəstəkləyir. CI pipeline daxildir: qurma → unit-testlərin işə salınması → UI-testlərin işə salınması → hesabatın dərci. JUnit hesabatı `xcodebuild` tərəfindən `-resultBundlePath` seçimi ilə yaradılır və istənilən CI alətinə idxal edilə bilər. Code Coverage — kodun hansı sətirlərinin testlə əhatə olunduğunu göstərən XCTest-in daxili funksiyasıdır. İstehsalat kodu üçün minimum əhatə həddi kritik biznes məntiqi üçün 70% təşkil edir.
Xcode Cloud və GitHub Actions `xcodebuild test -scheme App -testPlan SmokeTest` vasitəsilə XCTest-in işə salınmasını dəstəkləyir. CI pipeline daxildir: qurma → unit-testlərin işə salınması → UI-testlərin işə salınması → hesabatın dərci. JUnit hesabatı `xcodebuild` tərəfindən `-resultBundlePath` seçimi ilə yaradılır və istənilən CI alətinə idxal edilə bilər. Bitrise və Jenkins-in XCTest üçün hazır addımları var.
Code Coverage — kodun hansı sətirlərinin testlə əhatə olunduğunu göstərən XCTest-in daxili funksiyasıdır. Xcode əhatəni yaşıl (əhatə olunmuş), qırmızı (əhatə olunmamış) və sarı (qismən əhatə olunmuş) rənglərdə göstərir. Minimum hədd istehsalat kodu üçün kritik biznes məntiqi üçün 70% təşkil edir. Google Testing Blog (2024) məlumatlarına görə, bütün modullar üçün 80% əhatənin məcburi tələbi məntiqi yoxlamayan, ancaq kodu icra edən “boş testlərin” yaranmasına səbəb olur.
Tez-tez verilən suallar
XCTest — Xcode ilə birbaşa inteqrasiya olunan Apple-ın rəsmi framework-üdür. Quick və Nimble — BDD sintaksisi və daha oxunaqlı asersiyalar təmin edən üçüncü tərəf kitabxanalarıdır. Quick və Nimble Acceptance Testing üçün rahatdır, lakin XCTest xarici asılılıqların olmaması səbəbindən unit-testlər üçün daha etibarlıdır.
Asinxron kod XCTestExpectation + `wait(for:timeout:)` və ya XCTest-in `async/await` metodları (iOS 13+) vasitəsilə test edilir. Callback-əsaslı API üçün bağlamada çağrılan gözlənti yaradılır. async/await üçün async funksiyalarında standart asersiyalardan istifadə olunur.
XCTest daxili mock framework-ünə malik deyil. Mock etmə protokollar vasitəsilə həyata keçirilir: real asılılıqla eyni protokolu tətbiq edən mock sinifi yaradılır. Avtomatik mock yaradılması üçün Cuckoo, SwiftyMocky və ya əl mocklarından istifadə olunur. İnitializatorlar vasitəsilə Dependency Injection test üçün məcburi şərtdir.
Bəli, XCTest real cihazlarda Xcode və ya `-destination 'platform=iOS,name=iPhone 15'` parametri ilə xcodebuild vasitəsilə işə salınır. UI-testlər real cihazlarda simulyatorlardan daha dəqiq nəticələr verir. Cihaz fermalarında işə salmaq üçün BrowserStack, Sauce Labs və ya Firebase Test Lab istifadə olunur.
Swift Testing (2024) — `@Test`, `@Suite` və `@Expect` makroları ilə yeni Apple framework-üdür. O, daxili test paramETrizasiyası, suite-lərdə qruplaşdırma və daha oxunaqlı sintaksis təmin edir. Swift Testing XCTest ilə bir yerdə mövcuddur və onu əvəz etmir. XCTest UI-testlər və performance testləri üçün əsas framework olaraq qalır.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun