“Golang ile Uçtan Uca Proje Yapımı Serisi” 6. yazısında Go’da Kafka ile nasıl iletişim kurulabileceğinden, object mappingin nasıl yapılabileceğinden ve belki de en önemlisi test nasıl yazılabileceğinden bahsedeceğiz.
Message Broker
Önceki yazılardan hatırlarsanız Kafka üzerinden async bir logging yapısı kurmuştuk. Orada detaylarından bahsetmesem de shopify/sarama kütüphanesini kullanarak kodumuzun Kafka brokerlarına bağlanmasını sağlayarak mesaj alışverişi yapmıştık. Kodu tekrar bir hatırlayalım,
Burada brokerın adresine gönderilen acknowledge’ın karşılığında alınan acknowledge ile config yapılandırılıyor. Yine URL içerisinde iletilmesi beklenen retry policy de sarama config ine işlendikten sonra Producer instanceı yaratılıyor. En son mesaj göndermek istediğimizde de bu Producer üzerinden topiclerimize encode edilmiş veriyi gönderiyoruz. Benzer şekilde consumer örneğini de Sarama’nın sayfasından projeye ekleyebilirsiniz.
Object Mapping
Projelerimizde veritabanından aldığımız verileri tutan entitylerimizi servislerimizde input/output olarak kullanmamamız hem güvenlik önlemleri açısından hem de servislerimizin ihtiyaç duyduğu schema ile entitynin bilgilerinin %100 örtüşmeyebileceği açısından bir best practice. Bu sebeple entityleri Data Transfer Object(DTO) olarak isimlendirdiğimiz farklı objelere çevirip kullanırız.
Bu çevirimi yapmak için xconv kütüphanesini kullandım. Objelerdeki field isimlerini reflection ile dolaşıp yeni tipe mappingini sağlayan basit ve etkili bir kütüphane. Dilerseniz objelerdeki field isimlerinde birebir örtüşme olmadığı durumda tagleri de kullanacak şekilde kütüphaneye contributionda da bulunabilirsiniz.
Tests
Son olarak belki de en önemli konu testler. Kodumuzu her zaman test yapılabilecek şekilde yazmamız önemli bir konu. Bu sebeple TDD önem kazanıyor, çünkü önce testlerin sonra kodun yazıldığı bir senaryoda kodun teste uygun olmaması çok da mümkün değil. Ancak iyi bir TDD uygulayıcısı olmak bir anda gerçekleşen kolay bir şey değil. Çünkü dilin yeteneklerine hakimiyet zamanla gelişen bir şey. Hele de Golang gibi zengin bir dil ile çalışıyorsanız bir ihtiyacı görecek çok farklı şekillerde kodlar yazabileceğinizi zamanla göreceksiniz. Bu sebeple bu iş için önerilen best practiceleri öğrenerek bu işe atılmak iyi bir tercih olabilir.
Birim testlerimizi yazabilmek için Test Double’lara ihtiyaç duyarız. En yoğun kullanılan da muhtemeler Mock’lardır. İnterneti araştırdığınızda Golang için mocklama yapabileceğiniz çok farklı yöntemleri göreceksiniz; High Order Functions, Interface Substitution, Monkey Patching, Embedding Interface, vb… Bunlar içerisinde ana koda minimal etki ile en az eforlu mocklama yöntemlerinden 2 si için örnek kod paylaşacağım.
Embedding Interface
Kodlarda dikkatinizi çektiyse handler, service, repo gibi katmanlar arasındaki tüm iletişimler interfaceler üzerinden gerçekleştirildi. Bu testlerimizi yazarken mocklamayı kolaylıkla halledebilmek için yapılan bir tercih. Testini yazacağımız kodumuz şu şekilde;
Mocklama ihtiyacı duyduğumuz repositorynin görüntüsü;
Interfaceini taklit etmek istediğimiz sınıfın mocku olmak üzere bir struct tanımlıyoruz(14). Bu structa ait instance metodu olarak interfacete yer alan metodların implementasyonunu yapıyoruz(16). Bu mockun davranışının farklı test metotlarında değişiklik gösterebilmesi için test metotlarında editlenebilmesi ihtiyacı sözkonusu olduğundan instance metodunun dönüşünü(17) tanımladığımız bir First Class Function’a(12) devrediyoruz. Testin init fonksiyonunda(20) structımızı polymorphic olarak service(10) değişkenimize atayarak mock oluşturumumuzu tamamlıyoruz.
Sonrasında mockumuzun davranışını test metodunda tanımlayabiliriz. Bir anonymous function yardımıyla mocklamak istediğimiz metodun davranışını tanımladıktan sonra direk test edeceğimiz metodu çağırabiliriz. Bu kadar basit!
Monkey Patching
Eğer kodumuz instance metotları ile çağırılmayacaksa, direk bir metot olarak düşünülecekse metotlarımızı First Class Functions olarak tanımlayarak kolaylıkla mocklanmasını sağlayabiliriz. Örnek kod;
Örneğin burada normal bir fonksiyon yerine First Class fonksiyonu olarak tanımlanmış bir fonksiyon bulunuyor. Bunu test edebilmek için de aşağıdaki gibi bir kod yazmamız yeterli.
Son olarak, eğer kontrolü bizim elimizde olmayan bir kütüphanenin bir metodu mocklanması gerekirse de o kütüphanenin kullanıldığı satırı ayrı bir struct içerisindeki kendi yazdığımız bir metoda izole edip bu structa embedding interface yönteminde yaptığımız gibi polymorphic erişimle mocklanabilir hale getirebilirsiniz.
Serinin tüm yazılarına aşağıdaki linkler aracılığıyla erişebilirsiniz.
- Golang ile Uçtan Uca Proje Yapımı Serisi
- Golang Configuration Management
- Golang Central Logging Management
- Golang DB Migration - RDBMS & ORM Integration
- Golang API Management
- Golang Message Broker - Object Mapping - Testing
Yukarıda değindiğimiz bütün kodlara https://github.com/mehmetcemyucel/blog/tree/master/demo adresinden erişebilirsiniz.