[ARAÇ] SDL3 Birim Testler

Evet, sevgili yazılımperver dostlarım son yazılarımla birlikte artık SDL3 uygulamalarınızı oluşturmaya başladığınızı düşünüyorum. Bu yazılar ile birlikte, SDL3 giriş yapmış ve yazılım tasarım örüntülerini de kullandığımız temel bir örnek oluşturmuştuk.

[ARAÇ] SDL3 İlk Adımlar – I

[ARAÇ] SDL3 İlk Adımlar – II

Bu yazımızda ise, yazılım geliştirme sürecinin önemli bir parçası olan birim testlere eğilerek, en son geliştirdiğimiz uygulama için gerekli birim testleri (tabi ki yapay zeka yardımı ile 🙂 ) oluşturarak projemize ekliyor olacağız. Bunu yaparken nelere dikkat etmemiz gerektiğine, cmake’i nasıl kullanacağımıza ve ilgili test projesini nasıl oluşturacağımıza bakacağız.

Yazılım geliştirme hayatınız boyunca, vazgeçmememiz gereken (elbette istisnalar olabilir) en önemli hususlardan birisi de birim testlerdir. Birim testler, geliştirdiğiniz yazılımlarınızın gürbüzlüğü için ilk satıhtır. Bu testler ile ilk etapta temel kabiliyetleri doğrular sonrasında ise her değişiklikte yazılımın bütünlüğünün korunduğunu garanti altına almamıza yardımcı olur.

Birim testler geliştirilirken düşülen ikilemlerden birisi de, bunlara gerçekten vakit ayırmalı mıyızdır? Bazen bunlar vakit kaybı olarak da görünse de (ilk etapta elbette alt yapının ayağa kaldırılması ve birim testlerin yazılması için biraz emek gerekiyor), sonrasında bunun sizlere dönüşü ve kazancı çok daha büyük olacaktır. Neyse bu yazımızın amacı birim testler değil ama kısaca birim testlerin faydalarını sıralayıp, meraklı okuyucularımı daha önce bu minvalde kaleme aldığım yazılara yönlendiriyorum. Birim testlerin faydalarını kısaca sıralayacak olursak:

  • Kodun modülerize edilmesine, daha kolay test edilebilir parçalara ayrılmasına yardımcı olur,
  • Hatalar daha kolay ve hızlı bir şekilde bulmanıza olanak sağlar,
  • Her birim tarafından sunulan işlevsellik daha iyi anlaşılır,
  • Yazılımın hayat döngüsünde ileri zamanlarda yapılacak güncellemelerin doğru bir şekilde yapıldığından emin olunur (alt seviye regresyon testleri olarak düşünebilirsiniz),
  • Zaman kazandırır ve maliyeti düşürür.

Daha önce bu konuya değindiğim yazılara da aşağıdan ulaşabilirsiniz:

Birim Test Tavsiyeleri

Uygulama İzleme Yazılımı 3 – Utility, Birim Testler, Sürekli Entegrasyon

uEngine4 – GitHub Actions

Evet gelelim SDL3 örneğimize. Biz örneğimizde google test ve mock kullanıyor olacağız. Bu kütüphanelerin nasıl kullanılacağına da burada değinmeyeceğim, yukarıdaki yazılarda bunlara değindim.

Birim testler genel olarak kodlarımız ile birlikte yaşarlar ve dizin olarak da onlara yakın olurlar. Biz de benzer bir yaklaşım izleyeceğiz (aslına bakarsanız C++ şablon repomuzda da bu şekilde 🙂 ). Ana dizin altında bulunan “/test” dizini içerisinde ilgili test kodlarımız bulunuyor olacak.

Testleri yazdırmak için ise VsCode ile GitHub CoPilot’u kullanacağım. Belki ayrı bir yazıda, VsCode içerisinden, CoPilot’ı nasıl kullanacağımıza da değinebiliriz. Muhtemelen ürettiği kodlara ufak dokunuşlar yapmak gerekecektir ama bu aşamada sunacağı testlerin yeterli olacağını düşünüyorum.

İlk olarak ana proje dizininde bulunan cmake betiğine test dizinini ekliyoruz:

Bundan sonra uygulama kodlarımızı birim testlere nasıl dahil edeceğimize sıra geldi. Bunun için farklı yöntemler mevcut, biz burada genel kabul gören, ilgili kod parçalarını statik kütüphane haline getirip daha sonra bunu ilgili test projesinde bağlama yaklaşımını tercih edeceğiz.

Peki başka nasıl yapabiliriz? İlgili kod parçalarını ilgili test projesine ayrı ayrı ekleyebiliriz. Küçük projeler için bu olabilir ama projeniz büyüdükçe bu zor olacaktır.

CMake kullandığımız için statik kütüphane oluşturmak bizim için çok da sıkıntı olmayacak sadece aşağıdaki satırı eklememiz yeterli olacak. İlgili cmake betik dosyasını incelediğinizde, ana uygulama projesine de artık, kaynak kodları tek tek eklemiyor, yeni eklediğimiz statik kütüphane target’ını bağlıyoruz.

Bir sonraki adım, test projemiz için kullanacağımız google test kütüphanesinin ilgili birim test projesine dahil edilmesi olacak. Bunun için aşağıdaki güncellemeleri yapacağız cmake içerisinde. Bu satırlar ile cmake üzerinden, konfigürasyon zamanında ilgili kütüphaneyi indirerek derlemekte ve kullanımınıza sunmakta.

Bu ayarlamaları da yaptıktan sonra sıra geldi birim testlerimize. Bu yazımız için, birim testleri, asıl kaynak kodları yazdıktan sonra yazıyoruz ama bu açıkçası, yazı dizisinin anlam bütünlüğünü korumak için. Normal şartlarda, kendi yazılımınızı geliştirirken, sınıflarınız için birim testleri peyder pey yazıyor olmanızda fayda var. Her eklenen public fonksiyon için birim testlerinizi yazmaya başlayabilirsiniz.

Şimdi konumuza geri dönelim ve SDLResource sınıfımızdan başlayarak birim test yazmaya başlayalım dilerseniz. Bu sınıfımız bir önceki yazımızda RAII prensibine göre SDL kaynaklarının jenerik bir şekilde yönetilmesi için kullanabileceğiniz bir sınıf.

Bu sınıf için birim testleri üretmek için, SDLResource sınıfına giderek, ilgili kod parçasını seçip, copilot’a birim test üret dediğimizde muhtemelen sdl_resource_test.cpp deki gibi bir kod üretiliyor olacak. Burada, ilk değineceğimiz konu, birim test dosya isimlendirmesi. Herşeyde olduğu gibi burada bir standart izlemekte fayda var ve biz uygulamalarımızda “sınıf-ismi-test.cpp” isimlendirmesini takip ediyor olacağız.

Üretilen testlere yönelik değineceğim ikinci konu ise, birim testlerin isimlendirilmesi. Burada, açıkçası testlerin ne yapması gerektiğine odaklanarak, testin ne yapmayı hedeflediğini ifade edecek bir isimlendirme yapmayı tercih ediyorum. Bu bazen uzun olabiliyor, bununla birlikte birim testler için bunun bir problem teşkil etmediğini düşünüyorum. Elbette burada, birden fazla “and”‘ler ile bir şeyleri test edip/doğrulamaktan kaçınmakta fayda var.

Aşağıda, benim ürettiğim testleri görebilirsiniz:

Sınıfımız için gerekli birim testleri yazdıktan sonra gelelim üçüncü konuya. Birim test yazdık güzel de, bu testler geliştirdiğimiz kodların yüzde kaçını içeriyor. İşte buna birim test kapsama oranı diyoruz (uınit test coverage). Bunun ölçümü, birim testlerin koşturularak, buradan çağrılan fonksiyonları analiz edip hangi satırların çalıştırıldığı temeline dayanmakta (şimdi gidip ben elle bütün API’leri çağırsam, kapsama oranı %100 olmaz mı diye sorabilirsiniz, elbette olur ama bu da kendimizi kandırmaktan başka bir işe yaramaz öyle değil mi:) ).

Bu iş için de yine bir çok hazır araç bulunmakta. Ben burada linux için gcov + lcov ile gcovr‘u kullanacağım. Gcov, kapsama analizi verilerini üretiyor, lcov ile gcovr ise bunları kullanarak raporlama yapıyor. Windows için ise opencppcoverage aracı da oldukça kullanışlı bir araç.

Öncelikle bu araçları yüklememiz gerekiyor. Aşağıdaki satırlar ile bunları kurabilirsiniz:

Daha sonra, test projesinin cmake betiği içerisine aşağıdaki satırları ekliyorsunuz. Bu sayede derleyici, yazılım oluşturma aşamasında gerekli eklemeleri yapıyor.

Daha sonra build dizinini silip, test uygulamamızı baştan derleyelim. Sonra da testleri koşturalım ve aşağıdaki komutları çağıralım:

Yukarıdaki komutları /scripts dizini altındaki generate_coverage.sh betiği ile de çağırabilirsiniz.

Komutlar sonrasında /coverage_report/index.html ile kodunuzun ne kadarının testler ile kontrol edildiğini görüntüleyebilirsiniz. Benim çağırdığım koşum için görüntü aşağıdaki gibi:

Yukarıdakine benzer şekilde gcovr ile de raporlama almak için aşağıdaki komutları kullanabilirsiniz:

Umarım birim testler, bunların kullanımı ve neye hizmet ettiği konusuna yönelik kafanızda bir soru işareti kalmamıştır.

Güncel repoya aşağıdaki adresten ulaşabilirsiniz.

https://github.com/yazilimperver/cpp-playground

Bir sonraki yazımda, birim testleri de koşturduktan sonra yine yazılım geliştirmenin önemli bir parçası olan ve daha önce bir çok yazımda da bahsettiğim CI/CD adımlarına göz atıyor olacağız. O yazıma kadar kendinize iyi bakın, serin kalın 🙂

Kaynaklar

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.