Bakar mısınız? Önden bir test söylemiştik ama…

Selçuk Usta
Jan 30, 2019 · 4 min read

Şef muhtemelen ana yemeğe konsantre olduğu için, sizin aperitif yemek unutuldu sanırım!

Image for post
Image for post
Fotoğraf, Fabrizio Magoni tarafından çekilmiş, Unsplash’den indirilmiştir.

Uygulama geliştirirken de sıklıkla — ve refleks olarak — davrandığımız üzere; isteri karşılayacak olan algoritmayı ve algoritmayı sarmalayacak olan fonksiyonu tasarlarken davranışları gözardı ediyoruz. Oysa ki geçtiğimiz zamanlarda okuduğum (referansı hatırladığım an link ekleyeceğim) ve hala aklımda olan şu cümle çok önemli;

Fonksiyonları tasarlarken birincil endişe, algoritmalar değil davranışlar olmalıdır. Davranışlar ise algoritmaların seçimi konusunda sizi doğru kısıt ve yönlendirmelere itecektir.

Bu davranış sebebiyle de test yönelimli geliştirme (Test-Driven Development) kültürüne adaptasyonumuz zorlu oluyor, hatta bazen — ne yazık ki — olamıyor.

Test-Driven Development

Önce testi yaz, sonra fonksiyonu! yaklaşımı, işin en başından beri bana hep zor ve imkansız geldi. Düşünsenize, ortada bir fonksiyon yok ve siz olmayan bir fonksiyonu, olmayan parametrelerle çağırıyorsunuz; olmayan çıktıyı, olmayan bir sonuçla test ediyorsunuz. Bu imkansızlık senaryosu, yukarıda alıntıladığım cümleciği okuyana kadar geçerliydi ve oldukça zorlandım, açıkça itiraf etmek gerek. Sonra şunu farkettim:

Bir fonksiyon yazmaya karar verdiğimde içgüdüsel olarak kodu yazmaya başlıyorum. Burada “X” değişkenini 2'yle çarpsam ve gelen sonucu DB’ye sorsam, eğer DB’den gelen sonuç istediğim gibi ise Cookie’ye “true” değerini atarım. Cookie’ye de başarıyla yazdıktan sonra nihai sonucu geri döndürürüm.

Hadi şimdi gel de bunun testini yaz!?!

Yine içgüdüsel olarak fonksiyonun patlamaması için case’ler hazırladınız, değil mi? 48. satırda null kontrolü yapmışım, dur bir null geçeyim parametreyi, bakalım patlayacak mı?

Bu durumda biz algoritmayı test ediyoruz sanki, ancak amacımız bu muydu? Birim testimizin amacı, davranışın doğru sonuç vermesi değil miydi? Nasıl bir algoritma ile ilerlediği testin neyine?

Kafamızda canlanması için hadi gelin gerçek bir örnek yapalım. Örnek fonksiyonumuz oldukça basit. QueryString’den gelen parametreyi istediğimiz tipe çevirip döndürecek. ?param=5 gelen değeri, fonksiyon integer tipinde iletebilecek.

Image for post
Image for post

Herhalde çoğumuz, en basit haliyle yukarıdakine benzer bir kod yazardık diye düşünüyorum. Sonra da bu fonksiyona test yazmaya karar verdiniz (film yavaş yavaş kopmaya başlıyor).

Image for post
Image for post

Test’i çalıştırdınız ve BAM! Hiçbir test senaryonuz başarılı değil. Test’i debug ettiniz ve gördünüz ki 10. satırda kullandığınız HttpContext.Current objesi null geliyor. Sebebi ise oldukça basit; testin koştuğu ortamda herhangi bir HttpContext yok ki!

O kadar güzel kodladığınız blok ne yazık ki test edilebilir değil ve kişisel fikrim bu sebeple “güzel” de değil.

Test yönelimli geliştirseydim, nasıl olurdu?

Şu alıntıya tekrar dönelim mi? Diyor ki “davranışlar”. Eğer önce kodu yazmak yerine davranışı düşünseydim içimden şöyle bir cümle kurardım:

Ben bir fonksiyon yazacağım. QueryString’de istediğim anahtarda bir değer varsa o değeri alıp istediğim tipte geri döndürecek. Hmmmm… O zaman benim bu davranış için iki bağımlılığım var. Request nesnesi ve string tipinde bir anahtar değeri.

İşte bu! Fonksiyon kendini ortaya çıkartmadı mı sizce de? Bu metod iki parametre almalı. HttpContext ve string tipinde iki parametre. Hadi gelin şu kodu refactor edelim:

Image for post
Image for post

HttpContext bağlılığını sınıf seviyesinde tutuyorum ki, olur ya ilgili sınıf altındaki bir davranış daha bu bağımlılığa ihtiyaç duyarsa kullanabilsin diye. Sonra da ilgili bağlılığı fonksiyonum içerisine yediriyorum. Peki testi nasıl oldu bu fonksiyonun?

Image for post
Image for post

Gördüğünüz üzere, test ortamında kullanılmak üzere bir HttpContext sınıfı üretebiliyorum artık. Bu sanal sınıfı da, provider sınıfıma parametre geçebiliyorum. Böylece davranışı, gönül rahatlığıyla test edebiliyorum!

“Behind the Scenes”

Bu işin bir de kamera arkası var tabii. Bu işin arkasında “red — green — refactor” denilen teknik var. Kısaca şöyle özetlemek gerekirse;

  • (RED) Olmayan sınıfın instance’ını oluştur — 26. satır —

“Director’s Cut”

Yukarıdaki örnek bir .NET Framework örneğiydi. .NET Core bu konuda sizi “doğruya yönlendirmek” adına tabiri caizse sürüklüyor. Örneğin, fonksiyonlarınız içerisinde HttpContext diye bir sınıf kullanamıyorsunuz, çünkü yok. IHttpContextAccessor sınıfından türeyen HttpContextAccessor sınıfına ihtiyacınız var, bunu da mecburen DI ile ilgili sınıfa iletmeniz gerekiyor; gibi gibi senaryolar ile size yardımcı oluyor.

Hem yukarıdaki örneğin kaynak kodlarına hem de .NET Core örneğine aşağıdaki repository üzerinden ulaşabilirsiniz:

Sonuç

Yazılım geliştirme alışkanlıklarımızı değiştirmek oldukça güç ama unutmayın ki bu alışkanlığı da “edindiniz” ve yeni bir alışkanlıkla değiştirmemeniz için hiçbir neden yok. Üstelik daha değerli ve yararlı bir yöntem olduğunu bilmeniz motivasyon konusunda size yardımcı olacaktır. Değişim sürecine girmeye karar verirseniz, şimdiden başarılar! Bir sonraki yazıya dek, aperitifleriniz bol olsun — buraya kebapçı reklamı alınacaktır — :)

Selçuk Usta

Written by

Software Development Manager (at) Rasyotek. Former trainer & consultant. Family member of C# and Python. Newbie on Unix. Articles are mostly about coding.

Selçuk Usta

Written by

Software Development Manager (at) Rasyotek. Former trainer & consultant. Family member of C# and Python. Newbie on Unix. Articles are mostly about coding.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store