XCTest, iOS, macOS, watchOS ve tvOS için uygulamaların birim ve entegrasyon testi için Apple framework'üdür. XCTest, Xcode'un bir parçasıdır ve Swift ile Objective-C'de test yazmayı destekler. Üçüncü taraf framework'lerin (Quick, Nimble) aksine XCTest, Apple'ın resmi çözümüdür ve Xcode Server ile CI/CD'ye tamamen entegredir. Apple Developer (2024)'a göre XCTest, App Store'daki ilk 100 iOS uygulamasının %94'ünde kullanılmaktadır. XCTest, harici bağımlılıklar olmadan birim testleri ve kullanıcı arayüzü testleri yazmak için istikrarlı bir temel sağlar.
Önemli Noktalar
XCTest, Apple tarafından geliştirilen ve Xcode'a 5.0 sürümünden (2013) itibaren entegre edilmiş bir birim, entegrasyon ve kullanıcı arayüzü testi framework'üdür. XCTest, OCUnit'in (SenTestingKit) yerini aldı ve eşzamansız testler, performans testleri ve Xcode Server entegrasyonu desteğiyle modern bir Swift API'si sağladı. Swift.org'a (2024) göre XCTest, Swift Package Manager dahil tüm Apple projelerinde testlerin temelidir ve Swift Package Manager, kendi kendini doğrulama için XCTest'i kullanır.
XCTest, Xcode Test Navigator ve Report Navigator ile birlikte çalışarak test ağacını, çalıştırma geçmişini gösterir ve yapılar arasındaki sonuçları karşılaştırır. Test Navigator, kodu değiştirmeden tek bir testi, test grubunu veya tüm paketi çalıştırmaya olanak tanır. Sonuçlar yeşil (geçti), kırmızı (başarısız) ve sarı (atlandı) simgelerle görüntülenir. Apple WWDC (2024)'ye göre Xcode 16, birden çok simülatör kullanarak paralel test yürütmeyi %40 oranında iyileştirdi.
XCTest platformları destekler: iOS 8.0+, macOS 10.10+, watchOS 2.0+, tvOS 9.0+. Her platform aynı API'ye sahiptir ve bu da platformlar arası test yazmayı mümkün kılar. Swift Testing — Apple'ın yeni framework'ü (2024'te duyuruldu) — gelecekte XCTest'i tamamlayacak ancak tamamen yerini almayacaktır. XCTest, Apple ekosisteminde birincil test framework'ü olmaya devam etmektedir.
XCTestCase, XCTest'teki tüm test sınıflarının miras aldığı temel sınıftır. Test yaşam döngüsünü sağlar: her testten önce `setUp()` çağrılır, her testten sonra `tearDown()` çağrılır. setUp, nesneleri ve mock'ları başlatmak için kullanılır, tearDown ise kaynakları temizlemek için kullanılır. setUpWithError ve tearDownWithError, her testte try-catch olmadan başlatma hatalarını işlemeye olanak tanır.
Adı `test` ile başlayan her yöntem, Xcode tarafından otomatik olarak bir test olarak tanınır. Alternatif olarak, `@Test` makrosu (Swift Testing) kullanılabilir. Test adları açıklayıcı olmalıdır: `testLoginWithValidCredentials`, `testLogin1`'den daha iyidir. Yorumlar aracılığıyla testlerin belgelenmesi iyi bir uygulamadır, ancak Xcode, Kullanıcı Tanımlı Özellikler aracılığıyla açıklama eklemeye de izin 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")
}
}
Yukarıdaki örnek, standart XCTestCase yapısını göstermektedir. sut (Sistem Test Altında), test edilen nesne için bir adlandırma kuralıdır. MockURLSession, gerçek ağın yerini alarak UserService'in izole bir şekilde test edilmesini sağlar. “Bir test — bir iddia” ilkesi, hata ayıklamayı basitleştirir: bir test başarısız olursa, geliştirici hangi işlevselliğin bozuk olduğunu hemen bilir. Her XCTestCase testi, bir senaryoyu veya bir iddiayı doğrulamalıdır.
XCTAssertTrue ve XCTAssertFalse, boolean değerlerini kontrol etmek için temel iddialardır. XCTAssertTrue(expression), expression == true ise geçer. XCTAssertEqual, Equatable'ı uygulayan tüm türleri destekleyerek iki değerin eşitliğini kontrol eder. Kayan noktalı sayılar için, hesaplama hassasiyetini hesaba katmak üzere accuracy parametresiyle XCTAssertEqual kullanılır. Google Testing Blog'a (2024) göre XCTAssertEqual, tipik bir test paketindeki tüm kontrollerin %70'ini kapsar.
XCTAssertNil ve XCTAssertNotNil, isteğe bağlı değerleri nil için kontrol eder. Bu iddialar, isteğe bağlı türlerin yaygın olarak kullanıldığı Swift'te kritik öneme sahiptir. XCTAssertThrowsError, kodun beklenen bir hata fırlattığını doğrular. XCTUnwrap, isteğe bağlı bir değeri açan ve değer nil ise net bir mesajla başarısız olan bir iddiadır. XCTAssertEqual ile dize karşılaştırması, anlamsal değil, değişmez karşılaştırma kullanır. XCTAssertNoThrow, kodun hata fırlatmadığını doğrulamak için eşleştirilmiş iddiadır.
| İddia | Amaç | Örnek |
|---|---|---|
| XCTAssertEqual | Eşitlik kontrolü | XCTAssertEqual(a, b) |
| XCTAssertTrue | Doğruluk kontrolü | XCTAssertTrue(result) |
| XCTAssertNil | Nil kontrolü | XCTAssertNil(error) |
| XCTAssertThrowsError | Hata kontrolü | XCTAssertThrowsError(try parse("")) |
| XCTUnwrap | Optional açma | XCTUnwrap(value) |
XCTestExpectation, eşzamansız kodu test etmek için bir mekanizmadır. Test, açıklayıcı bir adla bir beklenti oluşturur, bunu eşzamansız bir işleme iletir ve `wait(for:timeout:)` çağrısı yapar. Beklenti, zaman aşımı içinde karşılanmazsa test başarısız olur. Zaman aşımı varsayılan olarak 10 saniyedir, ancak hızlı işlemler için genel test süresini hızlandırmak için 1-3 saniye ayarlanması önerilir.
XCTWaiter, wait(for:timeout:) için daha esnek bir alternatiftir. XCTWaiter, birden çok beklentiyi beklemeye, yürütme sırasını yapılandırmaya ve zaman aşımlarını programlı olarak işlemeye olanak tanır. wait'in aksine, XCTWaiter analiz edilebilen `XCTWaiter.Result` değerini döndürür. Temsilci XCTWaiterDelegate, beklenti sırası ihlalleri ve zaman aşımları hakkında bildirimde bulunur.
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")
}
Örnekte, XCTestExpectation eşzamansız bir oturum açmayı test etmek için kullanılır. fulfill(), geri arama closure'ı içinde çağrılarak eşzamansız işlemin tamamlandığını bildirir. 3 saniye içinde fulfill() çağrılmazsa, test zaman aşımıyla başarısız olur. Başarılı bekleyişin ardından, sonucu doğrulamak için iddialar gerçekleştirilir. Birden çok beklenti bir dizi olarak iletilebilir ve tümünün tamamlanması beklenebilir.
measure(metrics:), performans testleri oluşturmak için bir XCTestCase yöntemidir. measure içindeki kod bloğu art arda 10 kez çalıştırılır ve XCTest istatistikleri toplar: ortalama süre, medyan, standart sapma. Metrikler, izlenen metriklerin bir dizisidir: XCTClockMetric (zaman), XCTMemoryMetric (bellek), XCTStorageMetric (disk) ve XCTCPUMetric (işlemci). Apple WWDC (2024)'ye göre, XCTCPUMetric ile performans testleri algoritmalardaki gerilemeleri tespit etmek için kullanışlıdır.
Performans testleri için temel çizgi Xcode Test Planı'nda ayarlanır. Yürütme süresi, belirlenen bir yüzde (varsayılan %10) kadar temel çizgiyi aşarsa test başarısız kabul edilir. Temel çizgi, performans değişikliğinin beklendiği onaylandıktan sonra manuel olarak güncellenir. Xcode'daki Test Planı, performans testlerini yapılandırmalara göre gruplandırmaya olanak tanır: hata ayıklama/sürüm, farklı cihazlar, farklı iOS sürümleri.
func testArraySortPerformance() {
let numbers = (1...10000).shuffled()
measure(metrics: [XCTClockMetric()]) {
let _ = numbers.sorted()
}
}
Bu performans testi, 10.000 öğelik bir dizinin sıralama süresini ölçer. XCTClockMetric gerçek yürütme süresini yakalar. Sıralama algoritması değiştirildikten sonra süre %10 veya daha fazla artarsa, test bir gerileme olduğunu gösterecektir. XCTest performans testleri özellikle şunlar için kullanışlıdır: veri işleme algoritmaları, kullanıcı arayüzü bileşenlerinin oluşturulması, veritabanı işlemleri ve ağ istekleri.
XCTest'te test projesi yapısı kuralı takip eder: sınıf başına bir test dosyası, ayrı bir `<TargetName>Tests` dizinine yerleştirilir. Dosya adları, `Tests` sonekiyle test edilen sınıf adlarına karşılık gelir: `UserService.swift` → `UserServiceTests.swift`. Xcode'daki Test Hedefleri, birim testleri ve kullanıcı arayüzü testleri için ayrı ayrı yapılandırılır ve bağımsız olarak çalıştırılmalarına olanak tanır. Xcode'daki Şemalar, derleme yapılandırmasını ve çalıştırılacak test kümesini yönetir.
Xcode Cloud ve GitHub Actions, `xcodebuild test -scheme App -testPlan SmokeTest` aracılığıyla XCTest çalıştırmayı destekler. CI ardışık düzeni şunları içerir: derleme → birim testlerini çalıştırma → kullanıcı arayüzü testlerini çalıştırma → rapor yayınlama. JUnit raporu, `-resultBundlePath` seçeneğiyle `xcodebuild` aracılığıyla oluşturulur ve herhangi bir CI aracına aktarılabilir. Kod Kapsamı, testler tarafından hangi kod satırlarının kapsandığını gösteren yerleşik bir XCTest özelliğidir. Üretim kodu için minimum kapsama eşiği, kritik iş mantığı için %70'tir.
Xcode Cloud ve GitHub Actions, `xcodebuild test -scheme App -testPlan SmokeTest` aracılığıyla XCTest çalıştırmayı destekler. CI ardışık düzeni şunları içerir: derleme → birim testlerini çalıştırma → kullanıcı arayüzü testlerini çalıştırma → rapor yayınlama. JUnit raporu, `-resultBundlePath` seçeneğiyle `xcodebuild` aracılığıyla oluşturulur ve herhangi bir CI aracına aktarılabilir. Bitrise ve Jenkins'in XCTest için hazır adımları vardır.
Kod Kapsamı, testler tarafından hangi kod satırlarının kapsandığını gösteren yerleşik bir XCTest özelliğidir. Xcode, kapsamı yeşil (kapsanan), kırmızı (kapsanmayan) ve sarı (kısmen kapsanan) olarak görüntüler. Üretim kodu kapsamı için minimum eşik, kritik iş mantığı için %70'tir. Google Testing Blog'a (2024) göre, tüm modüller için %80 kapsam zorunlu kılındığında, mantığı doğrulamayan ancak yalnızca kodu çalıştıran “boş testler” ortaya çıkar.
Sıkça Sorulan Sorular
XCTest, Xcode ile doğrudan entegrasyona sahip Apple'ın resmi framework'üdür. Quick ve Nimble, BDD sözdizimi ve daha okunabilir iddialar sağlayan üçüncü taraf kitaplıklardır. Quick ve Nimble, Kabul Testi için uygundur, ancak XCTest, harici bağımlılıkların olmaması nedeniyle birim testleri için daha güvenilirdir.
Eşzamansız kod, XCTestExpectation + `wait(for:timeout:)` veya XCTest'in `async/await` yöntemleri (iOS 13+) aracılığıyla test edilir. Geri arama tabanlı API'ler için, closure'da karşılanan bir beklenti oluşturulur. Async/await için, async işlevlerinde standart iddialar kullanılır.
XCTest, yerleşik bir mock'lama framework'ü içermez. Mock'lama, protokoller aracılığıyla uygulanır: gerçek bağımlılıkla aynı protokolü uygulayan bir mock sınıfı oluşturulur. Otomatik mock oluşturma için Cuckoo, SwiftyMocky veya manuel mock'lar kullanılır. Başlatıcılar aracılığıyla bağımlılık enjeksiyonu, test edilebilirlik için zorunlu bir koşuldur.
Evet, XCTest, Xcode veya xcodebuild aracılığıyla `-destination 'platform=iOS,name=iPhone 15'` parametresiyle gerçek cihazlarda çalıştırılır. Gerçek cihazlardaki kullanıcı arayüzü testleri, simülatörlerden daha doğru sonuçlar verir. Cihaz çiftliklerinde çalıştırmak için BrowserStack, Sauce Labs veya Firebase Test Lab kullanılır.
Swift Testing (2024), `@Test`, `@Suite` ve `@Expect` makrolarına sahip yeni bir Apple framework'üdür. Yerleşik test parametrelendirmesi, paket gruplaması ve daha okunabilir sözdizimi sağlar. Swift Testing, XCTest ile birlikte var olur ve onun yerini almaz. XCTest, kullanıcı arayüzü testleri ve performans testleri için birincil framework olmaya devam eder.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun