20 Ocak 2018 Cumartesi

@Transactional Servise Mockito ile Mock Servis Enjekte Etme


Merhabalar. Bu yazımızda Java projelerimizde kullandığımız Mockito kütüphanesi ile, @Transactional anotasyonuna sahip bir servise mock servis enjekte edememe probleminden ve çözümünden bahsedeceğiz.
Öncelikle, neden mock (yapay, sahte) servis kullanıldığından bahsedelim. Unit test yazarken testin gerçekten unit olması için test ettiğiniz kod parçasının başka kodlara bağımlılığının olmaması gerekmektedir. Örneğin, sipariş toplam ücretini hesaplayan bir servis düşünelim. Ham ücrete eklenen vergi miktarını başka bir servisten hesaplatıp kullandığını düşünelim. Sipariş ücretini hesaplayan metodu sağlıklı test edebilmek için, vergiyi hesaplayan metoddan hatalı sonuç dönmeyeceğinden emin olmalıyız. Bu nedenle vergi hesaplayan metodun orjinal kodunu çalıştırmadan, doğrudan istediğimiz sonucu dönmesi için vergi servisini "mocklarız".

Mockito çatısını kullanırken bu işlemi @Mock anotasyonu ile yaparız. Test ettiğimiz servisin içindeki bir servise mock sevisimizi enjekte etmek için @InjectMocks anotasyonunu kullanırız. Yalnız, inject edilen servis @Transactional anotasyonuna sahip ise, enjekte işlemi gerçekleşmiyor. Çünkü, transactional servis, java proxy nesneye dönüştürüldüğü için, Mockito enjekte edecek sınıf elemanı bulamıyor. Bu problemi aşmak için, mock servisleri hazırladığımız sırada, ReflectionTestUtils kullanarak manuel olarak servisi enjekte ederek aşabiliriz.

Aşağıdaki kodlarla daha anlaşılır olacaktır.
"admin" kullanıcı adını dönen UserService.
UserService'den dönen kullanıcı adını customerName olarak dönen CustomerService.
UserService sınıfının getUserName metodunu mock user name dönmesini istememize rağmen, CustomerService @Transactional olduğundan içindeki UserService mocklanamadığı için test başarısız olmaktadır.
CustomerService içindeki UserService ReflectionTestUtils ile mocklandığı için, test başarılı sonuçlanmaktadır.

3 Ocak 2018 Çarşamba

Kötü Kod Alametleri - 2

Kodumdan Kötü Kokular Geldiğini Nasıl Anlarım? adlı yazımızda giriş yaptığımız kötü kod alametlerine devam edelim.


İsimden Bekleneni Yapmayan Metod

Örneğin,  isim ve soyisim parametresi alan bir Person sınıfı düşünelim. 

Person person = new Person("Ali", "Velioğlu");

Ben person nesnesinden ismi almak istediğimde kullanacağım metod 

String name = person.getName();

metodudur ve "Ali" dönmesini beklerim. Fakat metod bana "Ali Velioğlu" dönüyorsa, burada geliştiriciye çok can sıkıcı bir sürpriz hazırlanmış demektir. Sürprizlerden kaçınma ve bekleneni yapma prensibini benimsersek muhtemel onca hatayı daha oluşmadan engellemiş olacağız. (Based on a true story)

Mükerrer Kod (Dublikasyon)


Belki de en yaygın yapılan kod hatası budur. Zaman baskısı ve kolayımıza geldiği için hepimiz bu muhteşem COPY - PASTE kombinasyonunu kullanırız. Ancak bunun da bir maliyeti vardır. Hemen kopyalamak yerine, biraz daha efor sarfedip soyutlamaya ve ortaklamaya çalışmalıyız. Aynı kod satırlarının geçtiği yerler ortak bir metoda, hatta gerekiyorsa yeni bir sınıfa taşınabilir.

 Aşırı Yüklenmiş Sınıflar

 Örneğin, Long id değeri taşıması beklenen bir IdDto sınıfımız olsun.

public class IdDto {
private Long id;
 //getters & setters
}

Bu kadar basit. Bu sınıfın tek görevi id taşımak olmalı. Bu sınıfın kullanıldığı yerde name değerinin de taşınması ihtiyacı doğduğunu varsayalım. Üşengeç bir geliştirici gelip, IdDto sınıfı içerisine String name alanını eklerse bu sınıf aşırı yüklenmiş bir sınıf halini alacaktır. İsminin çağrıştırdığından fazla iş yapıyor olacaktır. Kırık camlar teorisine göre, diğer geliştiriciler doğacak yeni ihtiyaçlarda yine bu sınıfı şişirmeye devam edecektir. Aşırı yüklenen bu sınıf kodu daha kırılgan hale getirecek ve sonuçta tahmin edilemeyecek yeni hataların oluşmasına neden olacaktır. Çözüm ise, sınıf ismine saygı duyulmalı, kendisinden beklenmeyen yeni işler yüklenmemelidir. Yüklenecekse sınıf ismi terfi ettirilerek daha anlamlı hale getirilmelidir. (Based on a true story).

Ölü Kod

Program akışı içinde çalışması imkansız olan kodlara ölü kod diyoruz. Örneğin, her zaman false değer alan bir if içindeki kod ölü koddur. Ölü kodlar ihmal edilirlerse zombi yaşamlarına uzun süre devam edebilirler. Ve bu zombi kodlar bir süre sonra tasarım değişikliklerine ayak uyduramaz ve ayak bağı olurlar. Yapılması gereken en kısa sürede vedalaşıp koddan temizlemektir.  
 

Dikey Boşluk

Yerel değişkenler kullanıldıkları yere en yakın yerde tanımlanmalıdırlar. Bir değişken tanımını bulmak için sayfalarca yukarı scroll etmemeliyiz. Aynı şekilde, private metodlar da kullanılan metodun hemen altına tanımlanmalı ve içeriğine bakmak istediğimizde az bir aşağı scroll ile görebilmeliyiz.

Proje Gelenek Göreneklerine Saygısızlık


Her projenin takım içinde belirlenmiş  kod gelenekleri vardır. Örneğin, Enum değerleri büyük harlerle yazılmalı, Entity sınıflarının ismi Entity ile bitmeli, Servis sınıflarının interfaceleri Service ile implementasyonları ServiceImpl ile bitmeli gibi. Bu geleneklere uymadan yazılmış her kod, takım arkadaşınıza yaptığınız kötü bir sürpriz anlamına gelmektedir. Sürprizlerden kaçınmamız gerektiğinden bahsetmiştik. Api projesinde tanımlanması öngörülen bir interface'i başka yerde tanımlarsanız, onu olması gereken yerde göremeyen takım arkadaşınıza özür borçlu olduğunuzu unutmayın.

 

Yeterince Test Edilmemiş Kod

Yazdığımız testlerin kodumuzun yüzde kaçını kapsadığını bilmeliyiz. Bunun için test coverage araçlarını kullanabiliriz. Örneğin, Eclipse için EclEmma kullanılabilir. Bu araçlar, yazdığımız testlerin, kodun nerelerini çalıştırdığını, hangi değişik şartları test ettiğini, hangi şartların test edilmesi gerektiğini bize raporluyorlar. Test coverage takibini günlük kod geliştirme faaliyetimizin bir parçası haline getirmemiz, projenin sağlığına oldukça fayda sağlayacaktır.







Komut Satırından Google'lamak

googler isimli komut satırı aracı ile terminalden google aramaları yapabilir, sonuçlar üzerinde dolaşabilirsiniz. Ubuntu makinenize kurm...