Swift Unit Testing (Birim Testler)
Hatasız kod olmaz, ya da en azından pek fazla olmaz :) Peki çıktıları öngörülebilir ve tutarlı sistemler oluşturmak, kullanıcıya her seferinde daha iyi bir deneyim yaşatmak ve yazılım geliştiricileri olarak kendi işimizi kolaylaştırmak için ne yapmalıyız?
Bu yazımın tamamını okuduğunuzda birim test (Unit Test) hakkında temel bilgi sahibi olacak ve gerektiğinde (ortamlarda ya da profesyonel yaşantınızda) bu faydalı disiplinin olumlu katkılarını deneyimleyebileceksiniz. Yazımın son bölümünde de bonus bir tavsiye var, ona da mutlaka göz atmanızı öneririm.
Şimdi hızlıca konuya girelim.
Hata ayıklamada yaygın olarak kullanılan yöntemlerden biri hatanın test sorumluları ya da test kullanıcıları tarafından tespit edilmesidir. En istenmeyen senaryolarda ise hata kullanıcı tarafından fark edilir. Bu durumda da öncelik sıralamasına göre hatanın giderilmesi ve sistemin beklenen şekilde çalışır hale getirilmesi amaçlanır. Tüm bunlar bir geribildirim (feedback) sürecidir ve bu süreç tekrarlandığında sistemin beklendiği şekilde çalışır hale gelmesi muhtemeldir.
Ancak bu yöntem oldukça pahalı bir yöntemdir. Pahalıdır çünkü genellikle varlığından haberdar olunmayan, tekrarlanması güç hataları aramak ve kaynaklarını tespit edip gidermek ciddi bir zaman ve işgüçü gerektirir. Geçen sürede ürünün, markanın ve geliştiricinin itibarı zarar görebilir, kullanıcı kaybı yaşanabilir, kullanıcılar maddi ya da manevi zarara uğrayabilir. Siz de belki bu yazıyı okurken yaşadığınız pek de hoş olmayan bir hata ayıklama deneyimini hatırlıyor olabilirsiniz.
Peki ya tüm bu yavaş ve pahalı geribildirim sürecine alternatif olabilecek, bir çözüm mümkün müdür? Bu soruya cevabımız çoğu senaryo için ‘Evet, mümkündür. Peki nasıl? Çalışmasını beklediğimiz her bir birim (unit) ve ortaya çıkabilecek muhtemel senaryolar için test yazarak.
Bu yöntem bize yüzlerce hatta binlerce senaryoyu saniyeler içinde test etme imkanı sunmakla kalmayarak kod yazma anlayışımızı değiştirebilecek ve yazılım geliştirme maliyetini düşürebilecek kadar değerlidir.
Bir kod parçacığının ya da sistemin test kapsamına alınması, son kullanıcıya kesinlikle sorunsuz bir uygulama sunulacağı anlamına gelmez. Yine de, bu amaç için uygulanabilecek en iyi çözümlerden biri unit testlerdir.
Peki özet olarak nedir bu unit test? Özellikleri nelerdir diye soracak olursak;
- Unit test bir yazılım test etme metodudur. Bu yöntemde yazılımcı yazılım kodunu oluşturan birimlerin kullanıma hazır olduğuna iknâ olur.1
- Unit testler belirli bir önermeyi uygun koşullar oluşturularak test etmeye yarayan kod parçacıklarıdır.
- Testler basit, kolay okunabilir ve anlamlı şekilde isimlendirilmiş olmalıdır. iOS Unit test isimleri genellikle 3 bölümden oluşur ve alıştığımız camelCase yazım şekli yerine alt çizgi (_) ile bölümler birbirinden ayrılır. Örneğin:
test_load_emptyArrayFromCache
- Proje başlangıcında ya da sonradan eklenilebilirler. ( Test edilebilir şekilde yazılmamış sistemlere test eklendiğinde sistemin de değişikliğe uğraması gerekebilir. )
- Bu metodu disiplinli bir şekilde kullanarak yazılım geliştirme sürecine de Test Odaklı Geliştirme (Test Driven Development (TDD)) denir.
- Standartlara uygun şekilde yazılan unit testler verimli, esnek ve modüler bir mimari oluşturulmasına rehberlik görevi üstlenir.
Unit Test’in en önemli özelliklerinden bahsedecek olursak:
- Hızlıdır: Tek bir unit testin milisaniyeler içinde tamamlanması beklenir.
- Tekrar edilebilirdir: Aynı girdiyi alan unit testlerin aynı sonucu vermesi beklenir. Testlerin işlem sıralaması fark etmemelidir.
- Açık ve nettir: Başarısız olan bir unit test açıkça yakaladığı hatayı belirtmelidir.
Buraya kadar anlattıklarımı kısaca özetlemek gerekirse, unit testler güvenilir, bakımı ve geliştirmesi kolay ve ekonomik sistemler oluşturmak için kullanabileceğimiz önemli bir araçtır. Maddi ve manevi kayıpların önüne geçebilme imkanını geliştiricilere hızlı bir şekilde sağlar. Test Driven Development ise bu metodolojiyi izleyerek yazılım geliştirme sürecine denir.
Şimdi birlikte küçük bir örnek üzerinden unit testlere yakından bakalım.
İlk olarak XCode üzerinde yeni bir proje oluşturalım.
Şimdilik iOS app seçeneği ile ilerleyerek projemizi oluşturalım. (İleride Mac cihazımızın daha hızlı çözüm sunduğu örnekler de göreceğiz)
Projeye istediğiniz ismi verebilirsiniz. Bu örnekte Swift dilini kullanarak ilerleyelim. Include Tests kutucuğu işaretleyerek yeni proje başlangıcında kolaylıkla testleri projeye dahil edelim.
Daha sonra sol tarafta yer alan navigator menüsünden proje ismine uygun olan test dosyasını seçelim. Birkaç hazır işlevi bulunan test dosyamız hazır.
Bu aşamada bu işlevleri (fonksiyon, metod) kullanmayacağımız ve basitçe test oluşturmaya odaklanacağımız için bu işlevleri silebiliriz.
Sonrasında her şeyin sorunsuz çalıştığından emin olmak için test dosyamızı çalıştıralım. Bunun için sol üstte bulunan çalıştır butonuna, ya da test sınıfımızın hemen yanında bulunan butona tıklayabiliriz.
Daha da güzeli, sıklıkla lazım olacağı için şimdiden cmd + u kısayoluna elimizi alıştırmak olacaktır.
Her şey sorunsuz çalışırsa, (Bu aşamada biraz zaman alacaktır, simulatör kullandığımız ve UI Testleri de hazır olarak geldiği için) aşağıdaki gibi başarılı test sonucunu göreceğiz. Eğer kırmızı ile işaretlediğim ikon görünmediyse şu adımları takip edebilirsiniz.
Şimdi de basit bir test fonksiyonu ile ilk assertion (iddia, öne sürme, sav) örneğimizi test edelim.
- Bu fonksiyonda name adında bir sabit değer (constant) oluşturalım. Ben kendi adımı verdim, siz dilediğiniz değeri verebilirsiniz.
- Sonrasında iki değerin birbirine tam olarak eşitliğini test eden
XCTAssertEqual
fonksiyonunu kullanarak name ile “Eyüp Mert” sözcüklerinin tam olarak aynı olduğunu iddia edelim. - Sonuç olarak testimiz başarı ile tamamlanacak, tesminizin sonucu (Olumlu ya da olumsuz) bize hem ekranın altında çıkan ikon ve mesaj ile, hem de sol tarafta bulunan navigator menüsündeki test bölümünde açıkça iletilecektir.
Şimdi bir de başarısız sonuçlanan bir test örneğine bakalım. Bu örnekte name değerinin yani “Eyüp Mert” kelimelerinin “Eyüp” kelimesine eşit olacağını iddia ediyoruz. Ve test başarısız sonuçlanıyor. Aynı şekilde test sonucu hem navigator menüsünde, hem test ekranında hem de hatalı iddianın yanında beliren kırmızı yazıda bize iletiliyor.
- Ek olarak bu kırmızı yazıda testin başarısız olma sebebini de görüntüleyebilirsiniz.
Buraya kadar okuyup, adımları tekrarladıysanız tebrik ederim. Swift ile ilk testinizi yazmış oldunuz.
Anlamadığınız, açık olmadığını düşündüğünüz ya da ekstra anlatıma ihtiyaç duyduğunuz yerlerle ilgili benimle çekinmeden bağlantı kurabilir, irtibata geçebilirsiz.
Türkçe ve anlaşılır kaynak eksikliği olduğunu düşündüğüm konularla ilgili yazmaya devam edeceğim. Eğer bu yazıyı faydalı bulduysanız paylaşarak ya da alkış atarak destek vermeniz beni mutlu edecektir 🥳
Bonus Tip: Swift ile uygulama geliştirmek için kullandığımız XCode, kendi içinde bir code coverage ( test kapsamı ) aracı sunar. Bu araç yazılan kodun yüzde olarak ne kadar bir diliminin test kapsamına alındığını gösteren kullanışlı bir araçtır. ( Unutmamak gerekir ki esas amaç test kapsamını %100'e tamamlamak değildir. Güvenilir, geliştirilmesi ve bakımı kolay ve ekonomik bir sistem yaratmaktır. ) Yine de mümkün olan en yüksek test coverage amaçlanır. (Ancak %100 test coverage dahi sistemdeki tüm davranışların test edildiği anlamına gelmeyebilir.)
Sonuç:
- Unit testler bize (pek çok senaryo için) henüz ortaya çıkmadan hataları önleyebilme imkanı sunar.
- Manuel test yöntemlerine göre daha hızlı, ve ekonomik şekilde test ve geri bildirim imkanı sağlar.
- Geliştirdiğimiz yazılımın güvenilir olmasına ve stabil çalışmasına destek olur.
- Yazılım geliştirme, genişletme ve bakım maliyetlerini orta ve uzun vadede düşük tutmaya önemli ölçüde yardımcı olur.
- Uzun vadede sisteme yeni özellikler eklemeyi kolaylaştırır.
- Farklı geliştiricilerin birbirleri ile çakışan kodlar yazarak sisteme zarar vermesini önlemeye yardımcı olur. Buna gelecekteki kendimizi de (Yazdığımız kodun bütün işlevlerini uzun süre aklımızda tutamayacağımız için) dahil edebiliriz.
- Sistemin çalışmasını bozabilecek API (Uygulama Programlama Arabirimi) güncellemelerini hızlıca fark etmemize yardımcı olur.
Unutmamak gerekir ki iyi yazılım değişime ve gelişime açık olmalıdır. Çünkü işletme ihtiyaçları, müşteri talepleri ya da kullanıcı davranışları zaman içinde mutlaka değişecektir. Önemli olan bu değişikliğe ayak uydurabilmektir.
Siz de kendi yan projelerinizde ya da eğitim sürecinizde basit unit testler yazmaya başlayarak kod kalitenizi etkili bir biçimde arttırabilirsiniz. Bu yolda ilerlemek için unit testlerin temel taşları olan assertionları anlattığım yazıma mutlaka göz atmanızı, en azından sonra okumak için kaydetmenizi öneririm.
Referanslar:
- iOS Unit Testing by Example XCtest Tips and Techniques Using Swift, Jon Reid, sf 4
- The Lead Developer Essentials, Caio Zullo & Mike Apostolakis, 2020