En İyi Uygulamalara Git - Test Etme

Programlama kariyerimin ilk günlerinde, değeri gerçekten görmedim ve çoğunlukla kopyalandığını düşündüm. Şimdi ise genellikle yazdığım her şeyde% 90-100 test kapsamı hedefliyorum. Genelde her katman üzerinde yapılan testlerin iyi bir uygulama olduğuna inanıyorum (buna geri döneceğiz).

Aslında, günlük önümde sahip olduğum kod üslerine baktığımda, en çok değişiklik yapmaktan korktuğum kişiler, en az test kapsamına sahip olanlardır. Ve bu sonuçta verimliliğimi ve teslimatlarımı azaltır. Bu yüzden bana göre, yüksek test kapsamının hem daha yüksek kaliteye hem de daha yüksek üretkenliğe eşit olduğu oldukça açık.

Her katmanda test

Hemen bir örneğe dalacağız. Aşağıdaki yapıya sahip bir uygulamanız olduğunu varsayalım.

Uygulama modeli

Modeller ve işleyiciler gibi bazı paylaşılan bileşenler vardır. Öyleyse, bu uygulamayla etkileşimde bulunmanın birkaç farklı yolu var; CLI, HTTP API veya Thrift RPC'ler. Yalnızca modelleri veya yalnızca işleyicileri değil, hepsini test ettiğinizden emin olmak için iyi bir uygulama buldum. Aynı özellik için bile. Çünkü, işleyicide Feature X desteğini uyguladıysanız, örneğin aslında HTTP ve Thrift arabirimleriyle kullanılabildiği için doğru olabilir.

Bu, uygulamanızın özünde derinde olsa bile, mantığınızda değişiklik yapmak konusunda daha emin olacaktınız.

Masa bazlı testler

Neredeyse tüm durumlarda, bir yöntemi test ederken, işlevle ilgili birkaç senaryoyu test etmek istersiniz. Genellikle farklı giriş parametreleri veya farklı alay yanıtları ile. Tüm bu testleri tek bir Test * işlevinde gruplandırmayı seviyorum ve sonra tüm test durumlarında çalışan bir döngü var. İşte temel bir örnek:

func TestDivision (t * testi.T) {
    sınamaları: = [] struct {
        x float64
        y yüzer64
        sonuç float64
        hata
    } {
        {x: 1.0, y: 2.0, sonuç: 0.5, hata: nil},
        {x: -1.0, y: 2.0, sonuç: -0.5, err: nil},
        {x: 1.0, y: 0.0, sonuç: 0.0, hata: ErrZeroDivision},
    }
    _ için, test: = aralık testleri {
        sonuç, hata: = bölme (test.x, test.y)
        assert.IsType (t, test.err, err)
        assert.Equal (t, test.result, sonuç)
    }
}

Yukarıdaki testler her şeyi kapsamamaktadır, ancak beklenen sonuçların ve hataların nasıl test edileceğine örnek teşkil etmektedir. Yukarıdaki kod aynı zamanda iddialar için mükemmel ifade paketi kullanır.

Adlandırılmış test durumları ile geliştirme, tablo tabanlı testler

Kod tabanına aşina olmayan birçok testiniz veya sıklıkla yeni geliştiricileriniz varsa, testlerinizi adlandırmanız yararlı olabilir. İşte neye benzeyeceğinin kısa bir örneği

testler: = map [string] struct {
    sayı int
    smsErr hatası
    hata
} {
    "başarılı": {0132423444, nil, nil},
    "hata yayılır": {0132423444, sampleErr, sampleErr},
}

Burada bir haritaya sahip olmakla dilim arasında bir fark olduğunu unutmayın. Dilim, haritanın düzeni garanti etmiyor.

Alay kullanarak alay

Arayüzler testler için doğal olarak süper iyi entegrasyon noktalarıdır, çünkü bir arayüzün uygulaması kolayca sahte bir uygulama ile değiştirilebilir. Ancak, sahte yazılar yazmak oldukça sıkıcı ve sıkıcı olabilir. Hayatı kolaylaştırmak için verilen bir arayüzü temel alan sahte ürünlerimi oluşturmak için alaycı kullanıyorum.

Bununla nasıl çalışılacağına bir göz atalım. Aşağıdaki arayüze sahip olduğumuzu varsayalım.

SMS arayüzünü yazın
    Gönder (sayı int, metin dizesi) hatası
}

İşte bu arayüzü kullanarak sahte bir uygulama:

// Messager, çeşitli tiplerde mesajlaşma yapan bir yapıdır.
Messager yapı tipi {
    sms sms
}
// SendHelloWorld, bir Merhaba dünyaya SMS gönderir.
func (m * Messager) SendHelloWorld (sayı int) hatası {
    err: = m.sms.Send (sayı, "Merhaba, dünya!")
    eğer err! = nil {
        geri dönüş
    }
    geri dönüş
}

Artık SMS arayüzü için bir alay oluşturmak için Mockery'i kullanabiliriz. İşte neye benzeyeceğini açıklıyor (bu örnek, sahneyi arayüzle aynı pakete koyan -inpkg bayrağını kullanıyor).

// MockSMS, SMS tipi için otomatikleştirilmiş bir sahte tiptir.
MockSMS struct yazın {
    mock.Mock
}
// Gönder, verilen alanlarla alay işlevi sağlar: sayı, metin
func (_m * MockSMS) Gönder (sayı int, metin dizesi) hatası {
    ret: = _m.Called (sayı, metin)
    var r0 hatası
    eğer rf, ok: = ret.Get (0). (func (int, string) hatası); tamam {
        r0 = rf (sayı, metin)
    } Başka {
        r0 = ret.Error (0)
    }
    r0 döndür
}
var _ SMS = (* MockSMS) (sıfır)

SMS yapı, tanıklık mock.Mock'tan miras alıyor, bu da test senaryolarını yazarken bize bazı ilginç seçenekler sunuyor. Öyleyse, Mockery’deki sahte yazılımı kullanarak SendHelloWorld yöntemi için testimizi yazmanın zamanı geldi.

func TestSendHelloWorld (t * testi.T) {
    sampleErr: = errors.New ("bazı hata")
    testler: = map [string] struct {
        sayı int
        smsErr hatası
        hata
    } {
        "başarılı": {0132423444, nil, nil},
        "hata yayılır": {0132423444, sampleErr, sampleErr},
    }
    _ için, test: = aralık testleri {
        sms: = & MockSMS {}
        sms.On ("Gönder", test.number, "Merhaba, dünya!"). Dönüş (test.smsErr) .Once ()
        m: = & Messager {
            sms: sms,
        }
   
        err: = m.SendHelloWorld (test.numarası)
        assert.Equal (t, test.err, err)
        sms.AssertExpectations (t)
    }
}

Yukarıdaki örnek kodda bahsetmeye değer birkaç nokta var. Testte, MockSMS'i başlattığımı ve ardından .On () 'ı kullanarak bazı parametreler alaycıya gönderildiğinde ne olması gerektiğini (.Return ()) belirleyebilirim.

Sonunda, SMS arayüzünün beklenen sayıda çağrıldığından emin olmak için sms.AssertExpectations kullanıyorum. Bu durumda Once ().

Yukarıdaki tüm dosyalar bu özünde bulunabilir.

Altın dosya testleri

Bazı durumlarda, büyük bir yanıt bloğunun aynı kaldığını iddia etmenin yararlı olacağını gördüm. Örneğin, bir API'den JSON verilerinden döndürülen veriler olabilir. Bu durumda Michell Hashimoto'dan akıllı ile birleştirilmiş altın dosyaların kullanımı hakkında bir şeyler öğrendim.

Temel fikir, bir dosyaya (altın dosya) doğru yanıt gövdesini yazmanızdır. Sonra testleri çalıştırırken, altın dosya ile test yanıtı arasında bir bayt karşılaştırması yaparsınız.

Kolaylaştırmak için komut satırı bayrağı ayarını ve altın dosya yazmayı ve karşılaştırmayı şeffaf bir şekilde ele alan goldie paketini oluşturdum.

İşte bu test türü için goldie'nin nasıl kullanılacağına bir örnek:

func TestExample (t * testi.T) {
    kaydedici: = httptest.NewRecorder ()

    req, err: = http.NewRequest ("GET", "/ example", nil)
    assert.Nil (t, err)

    işleyici: = http.HandlerFunc (ExampleHandler)
    handler.ServeHTTP ()

    goldie.Assert (t, "örnek", kaydedici.Body.Bytes ())
}

Altın dosyanızı güncellemeniz gerektiğinde aşağıdakileri çalıştırırsınız:

teste git -update. / ...

Ve sadece testleri yapmak istediğinizde, bunu her zamanki gibi yaparsınız:

Teste git.

Güle güle!

Sonuna kadar geldiğin için teşekkürler! Umarım makalede yararlı bir şey bulmuşsundur.