Merhabalar yazılımperver dostlarım, bu yazımda, birim test geliştirirken sizler için faydalı olacağına inandığım bir takım önerileri sizler ile paylaşıyor olacağım.
Daha önce Uygulama İzleme Yazılımı 3 – Utility, Birim Testler, Sürekli Entegrasyon yazımda, birim test konusuna değinmiş, bir takım faydalarını sıralamış ve Uygulama İzleme Yazılımında kullanımını, bazı kütüphaneler ile birlikte sizlerle paylaşmıştım. Tekrar hatırlayacak olursak, aslında birim testler ile birlikte:
- Kodunuzun beklendiği gibi çalıştığından emin olmanıza yardımcı olur,
- Bir takım hataları önceden bulup düzeltmemize yardım eder,
- Kodların değişiklikler ile birlikte sağlamlığını korumasına yardım eder ve “refaktor” ederken kafanızın daha rahat olmasını sağlar,
- Kod kalitesini arttırır,
- Kodun anlaşılmasına yardım eder.
Bu yazımda ise, kılavuz niteliğindeki önerileri, madde madde sizler ile paylaşacağım. Daha fazlası için de, bir takım kaynakları yazımın sonuna ekliyorum. Haydi başlayalım:
- Birim testleriniz kısa ve hızlı olmalıdır.
- Neden? Geliştirici her kodu “commit”/”check in” yaptığında hızlıca çalışmalı ve sonuçları göstermelidir,
- Birim testler olabildiğince otomatize ve dışarıdan müdahale ihtiyacı olmamalıdır,
- Birim testlerde ne kadar manuel müdahale olursa o kadar verimlilik düşer. Süreç olabildiğince otomatik ve düzenli bir şekilde uygulanabiliyor olmalıdır,
- Testleriniz okunabilir olmalıdır.
- Testleriniz de kodlar gibi bir süre sonra okunabilirliğini kaybedebilirler. Hatta, bu çok daha kolay ve hızlı olabilir.
- Bu bağlamda “arrange, act, assert” mantığına sadık kalın,
- Testleri olabildiğince basit tutun,
- Sihirli sabitler ya da metinlerin kullanımından kaçının,
- Testlerin aynı zamanda koda ilişkin bir kılavuz/dokümantasyon olduğunu unutmayın,
- Testlerinize ilişkin ölçümleri unutmayın, özellikle kapsama analizi göz ardı edilmemelidir.
- Testler ile birlikte kodun kapsandığı satırlarının takip edilmesi, testlerin etkinliği için önemli bir noktadır,
- Kapsama analizi yaparken, öncelikle koşum kapsamına daha sonra test kapsamına öncelik verin.
- Kapsama analizleri genelikle koşturulan satırları kolay bir şekilde verse de, test ile kapsanan satırları (gerçekten test edilen) tespit etmek o kadar kolay olmayabilir,
- Koşum kapsamı sağlandıktan sonra, koşul kontrolleri için her koşulun veya değerin doğrulandığı kontrol edilmelidir,
- Başarız testlerin olabildiğince hızlı çözülmesini sağlayın.
- Gerek süreçsel gerekse kültürel olarak, ekibin kalan testleri hızlı bir şekilde çözmesini sağlayın,
- Birim testleri, birim seviyesinde tutun.
- Birim testlere ilişkin en önemli konulardan birisi de, ilgili testlerin seviyesidir. C++ için bu sınıfların “public” fonksiyonlarıdır,
- Burada ayrıca birim testler ile bütün akışın test edilmesine aşırı bir ağırlık verilmemesine de dikkat edilmelidir. Birincil öncelik sınıfın davranışlarıdır, sonrasında, kritiklik durumuna göre akışlar da test edilebilir,
- Dışa bağımlı olan veya kullanılacak diğer servisler “mock” lar aracılığı ile kullanılmalıdır. Olabildiğince gerçek sınıf kullanılmamalıdır,
- Birim testlerinin, entegrasyon testlerine dönüşmesine izin vermemelisiniz.
- Basit testlerden başlayın, TDD adımlarını takip edebilirsiniz.
- Birim testlerin hiç yazılmamasındansa, testlerin olması çok büyük fark yaratır. Bu sebeple çok karmaşık testlere yoğunlaşarak, test yazımından uzaklaşmayın,
- Basit testler ile başlayın, aynı kod gibi “refaktör” ederek, testlerinizi de güncel tutun,
- Testlerinizde tek bir kullanım durumuna odaklanın.
- Açıkçası bir çok yerde karşılaştığım önerilerden birisi de bu oldu. Bunun farklı yaklaşımları mevcut.
- Ör. En fazla bir “assertion” olsun, tek bir kullanım durumunu test edin, vb.
- Her ne kadar tek bir “assertion” biraz zor bir hedef olsa da, tek bir kullanım durumunun test edilmesi önemli bir konu,
- Aynı test içerisinde hem dosyaya yazma hem de “standard output”‘a yazmayı test etmemelisiniz,
- Sınıflarınızın public API’lerini ve açık olan (ya da öyle görünen) davranışlarını test edin.
- Bir önceki kalem ile de ilintili olarak, basit setter/gettter bile olsa, bu tarz “public” API’leri muhakkak test edin,
- Bu tarz genelde, basit isimlendirme değişiklikleri ya da kopyala/yapıştır hatalarının önüne geçecektir,
- Benzer şekilde, bariz gibi görünen koşulları da test etmeyi ihmal etmeyin,
- Testleriniz birbirinden bağımsız olmalıdır.
- Testlerin bakımı ve stabil olması adına birbirlerinden bağımsız olmalıdır,
- Sıra bağımlılığı olmamalıdır. Hatta google test gibi bir takım kütüphaneler özellikle sıralamayı her koşum için rastgele değiştirebilmektedir,
- Testlerinizi doğru bir şekilde isimlendirin.
- Aslında benzer bir sıkıntı, değişken, fonksiyon ve sınıflar için de geçerli: isimlendirme,
- Testlerin sınıfın hangi kabiliyetini test ettiğini açık bir şekilde isminde ifade edin,
- Testlerinizi tasarlarken farklı seviyelerde düşünün.
- Testleri hazırlarken, tasarlarken, ilgili sınıfların müşterisi gibi düşünün,
- Dah sonra da, geliştirdiğiniz sınıfa ilişkin sunmak istediğiniz servisleri düşünerek testlerinizi hazırlayın.
- Testlerinizde sınır değerleri es geçmeyin.
- Özellikle gömülü yazılımlar ve emniyet kritik yazılımlar geliştiriyorsanız buna aşina olabilirsiniz ama standart uygulamalarda da sınır değerlerini test ediyor olmak size büyük güvence sağlayacaktır,
- Boş dosya, sınır dışı sayılar, negatif sayılar, vb. durumlar,
- Negatif testleri de göz önünde bulundurun.
- Özellikle kodun kullanılmaması gereken koşulları da test etmeniz, kodunuzun sağlamlılığını arttıracaktır,
- Kodu tasarlarken, testi de muhakkak göz önünde bulundurun.
- Birim testlerin yazılması maliyetli ve bakımları da zor olabilmektedir. Dolaylı olarak test edilen sınıfların da basit olması testlerin yazılmasını da, bakımını da kolaylaştıracaktır,
- Peki neler yapılabilir?
- Public API’ler az tutulabilir (tabi ki her şeyi “private” yapın demiyorum 🙂 )
- Yapıcı ile birlikte sınıfa dair değişmeyecek, durumları atayarak, “setter” sayısını azaltabilirsiniz,
- Miraz ve sanal “public” fonksiyon kullanımını limitleyebilirsiniz,
- Gereksiz koşul (if, switch) kontrollerinden kaçının,
- Koşullar içerisindeki kodları minimize edin,
- Kısacası kodu basitleştirebilecek her şeyi yapın 🙂
- Bildirilen hataları tekrarlayacak testleri yazın.
- Bence bir diğer önemli konu, birim testlerde çıkmayan fakat, herhangi bir zamanda ortaya çıkan hatalara ilişkin test kodlarının yazılması,
- Ne zaman bir hata bildirilse, ilk iş bunun (elbette oluşturulabiliyorsa) o hatanın oluşturulduğu bir test kodu yazmak, sonra kodu düzeltmek ve ilgili testin geçtiğini gözlemlemektir,
- Birim testlerine ilişkin sınırları aklınızdan çıkarmayın.
- Son olarak şunu hiç unutmayın ki, birim testler, kodun yüzde yüz çalıştığı anlamına gelmez,
- En büyük faydası, güncellemelerden etkilenmediğini, yeni geliştirilen kodların öncekileri bozmadığını ve tutarlılığını koruduğunu aklınızdan çıkarmayın.
- Testleri yazmak için bir test pratiği/yaklaşımı belirleyin
- Yazılım geliştirme süreçlerine paralel şekilde, sağlıklı bir test yazımı için, TDD ya da benzeri yaklaşımları takip etmek, test geliştirme sürecini hayatta tutmanıza yardımcı olur,
Benzeri öneri içeren diğer kaynaklar ve birim testlere ilişkin daha detaylı bilgiler için aşağıdaki kaynaklara göz atabilirsiniz 😉
Önerileri olabildiğince basit, kısa ama anlaşılabilir kılmaya çalıştım, umarım faydalı olmuştur. Bir sonraki yazımda görüşmek dileğiyle, bol kodlu günler diliyorum.
Kaynaklar
- https://www.testim.io/blog/unit-testing-best-practices/
- https://www.toptal.com/qa/how-to-write-testable-code-and-why-it-matters
- https://dzone.com/articles/unit-testing-best-practices-how-to-get-the-most-ou
- https://www.artofunittesting.com/definition-of-a-unit-test/
- https://stackoverflow.com/questions/106800/unit-testing-guidelines