Golang ve Unit Test Yazma

/images/posts/mycodecantfail.jpg

Merhaba bu yazıda Golang ile unit testing işlemlerinin nasıl yapılacağını size aktarmaya çalışacağım. Çoğu programcı buna ben de dahil fail senaryolarını test etmeyiz. Kimimiz bunun bilincindeyiz kimimiz ise test işlemlerinin çalışan sistemde gerçekleştirilenden ibaret olduğunu düşünmekte.

Ancak fail senaryoları bazen çalışan sistemde yaşanacak yanlışlıkları henüz o türlü bir test aşamasına gelmeden önce engellememize yardımcı olabilir.

Profesyonel bir yazılımcısınız yani 10 yıllık geçmişiniz var ancak buna rağmen hatalarınız çıkabiliyor. Örneğin müşterilere belirli zaman aralıklarında SMS atan bir fonksiyonumuz var. Bu fonksiyona girilen telefon numarası minimum 7 karakter olmalı. Fakat bir müşterimiz 6 karakter girmiş. Haliyle SMS gönderilmiş olsa bile yanlış bir numaraya gitmiş olacak.

Bunun nedeni ise gerekli doğrulamayı gerçekleştirilen metodu belki de tam anlamıyla beklendiği gibi yazmayışımız.

Ne Yapmalıyım

/images/posts/unittest.jpg

Kedi arkadaşın dediği gibi unit testler ile mantıksal hataların önüne geçebileceğimiz bazı testler yazabiliriz.

Go Dilinin Varsayılan Olanağı

Bu yazının devamı olur mu bilmiyorum ama şu an için bu yazıda testing isimli modülü kullanacağız. Dosya isimlendirmesi ise şöyle olmalı. MUST

dosya.go
dosya_test.go

Ardından sms işlemlerini gerçekleştireceğimiz şöyle 2 dosya oluşturalım:

sms.go
sms_test.go

Buradan anlayacağımız şey test dosyaları mutlaka suffix olarak _test almalı. Hemen sms.go dosyası için basit bir doğrulayıcı metod yazalım:

func CheckPhone(phone string) bool {
    if len(phone) >= 7 {
        return true
    } else {
        return false
    }
}

Yukarıda söylediğimiz senaryoya göre ilerliyoruz. Bu kodumuzun sms.go içerisinde olduğunu unutmayan hemen sms_test.go dosyası için de testimizi yazalım:

package sms

import "testing"

func TestCheckPhone(t *testing.T) {
    kontrol := CheckPhone("1234567")

    if kontrol {
        t.Log("Test başarılı")
    } else {
        t.Fatalf("Telefon karakter sayısı geçemedi", kontrol)
    }
}

Burada vereceğiniz mesajlar testing modülünden geliyor ya da paket diyelim biz buna. Yukarıdaki kodda dikkat etmemiz gereken ilk şey öncelikle import "testing" ifadesidir. Kısacası testing modülünü çağırdık.

Ancak buna rağmen eğer doğru isimlendirmeyiz yapmazsanız testleriniz go dili yorumlayıcısı tarafından bulunamayacaktır. Go programlama dilinde yazılan tüm testler Test prefix’i ile başlamalıdır. Yukarıda yazılı testi çalıştıralım. Test dosyalarını go run parametreleri ile çalıştıramazsınız. Bunun yerine bulunduğunuz dizinde go test ya da go test -v parametrelerini verebilirsiniz. Her iki parametrenin de verdiği çıktıya göz atalım:

go test

--- FAIL: TestCheckPhone (0.00s)
    sms_test.go:11: Telefon karakter sayısı geçemedi%!(EXTRA bool=false)
FAIL
exit status 1
FAIL    _/home/ali/Projects/go/go_unit_test 0.001s

go test -v

=== RUN   TestCheckPhone
--- FAIL: TestCheckPhone (0.00s)
    sms_test.go:11: Telefon karakter sayısı geçemedi%!(EXTRA bool=false)
FAIL
exit status 1
FAIL    _/home/ali/Projects/go/go_unit_test 0.001s

Farklı olan tek şey hangi test metodunun çalıştırıldığını da görebiliyor oluşumuz. Peki birden fazla test yazar mıyız? Elbette yazarız. Çoğu go projesi birden fazla dosyayı içerisinde barındırmaktadır. Örneğin email doğrulayan bir paketimiz daha olsun. Bu durumda yapımız şöyle değişiyor:

sms
    --- sms.go
    --- sms_test.go
email
    --- email.go
    --- email_test.go

Örneğin şöyle bir email doğrulama fonksiyonuna sahip olalım:

package email

import "regexp"

func CheckEmail(mail string) bool {
    match, _ := regexp.MatchString("[^@]+@[^@]+\\.[^@]+", mail)

    return match
}

Bu fonksiyon girilen email adresinin doğruluğunu kontrol eder ve true ya da false sonuç döndürür. Mükemmel bir doğrulayıcı da değil bu arada bunu referans almayın. Şimdi bunun testini yazalım:

package email

import "testing"

func TestEmail(t *testing.T) {
    check := CheckEmail("ahmetin_maili~et~yokmail.com")

    if check {
        t.Log("Test başarılı")
    } else {
        t.Fatalf("Girilen mail adresi testi geçemedi")
    }
}

Test için verdiğimiz komut satırı parametreleri biraz evrimleşecek ve şöyle olacak:

go test ./... -v

Bu tüm dizinleri dolaşıp orada yer alan test dosyalarını test edecektir. Bu parametreden sonra çıkan sonucumuz şöyle oluyor:

=== RUN   TestEmail
--- FAIL: TestEmail (0.00s)
    email_test.go:11: Girilen mail adresi testi geçemedi
FAIL
FAIL    _/home/ali/Projects/go/go_unit_test/email   0.001s
=== RUN   TestCheckPhone
--- PASS: TestCheckPhone (0.00s)
    sms_test.go:9: Test başarılı
PASS
ok      _/home/ali/Projects/go/go_unit_test/sms 0.001s

Evet bu yazıda kısaca go programlama dili ile bir unit test nasıl gerçekleştirilir onu görmüş olduk. Umarım faydalı olur.