Birim Testi Geliştirme Prensipleri

Birim Testi Geliştirme Prensipleri

Tanım

Bu belge birim testi geliştirirken gözetilmesi ve uygulanması gereken prensipleri içerir.

Genel Prensipler

  • Her sınıf için ayrı bir test dosyası oluşturmak doğru olacaktır. (Fixture-Per-Class: Her sınıfın bir test sınıfının olduğu geliştirme yöntemi)

  • Testler Dokümantasyon Olarak Test (Test as Documentation) amacıyla da oluşturulur.

  • Testler test edilemeyen kodlar olduğu için testler olabildiğince basit tutulmalı, tekrarlanan veya karmaşık işlemler Yardımcı Metotlar veya Test Utility Method lara taşınmalı, bu kodlar test edilmelidir.

  • Kod tekrarı ndan kaçınılmalı, bu durumlarda Yardımcı Metotlar veya Test Utility Method lar kullanılmalı, bu kodlar test edilmelidir.

Elle Verilen Değerler

  • Kurulumlarda veya doğrulamalarda kullanılan değerler test içinde elle verilmemeli, yardımcı metotlar kullanılmalıdır.

  • Bu gibi değerlerin fazla olması testi belirsiz ve karmaşık hale getirir. Setup ile Assert arasındaki neden-sonuç ilişkinin okunup anlaşılamamasına neden olur.

Belirsiz Test (Obscure Test)

  • Belirsiz Test (Obscure Test) geliştirmekten kaçınılmalıdır. Bu tip testler aşağıdaki gibi belirtilere sahiptir:

    • Anlaşılmaz isimlendirmeler

    • Fazla kod

    • Koşullu mantıklar

  • Belirsiz Test (Obscure Test)

    • Dokümantasyon Olarak Test (Test as Documentation) niteliğinin kaybedilmesine neden olur.

    • Bakımı zordur.

    • Test hatası veya uygulama kodu hatası oluşmasına zemin hazırlarlar.

Her Koşul = Yeni Test

  • Her birim testi sadece bir koşulu test etmelidir.

  • Testlerde koşullu ifade mantıkları (if, switch, vb. kullanılmamalıdır.)

  • if, switch, for, foreach blokları testleri karmaşıklaştırır. Farklı durumların kendine özel testleri olmalıdır.

  • Koşullu ifade kullanmak yerine Guard Assertion kullanılabilir. (Örneğin bir nesnenin null olmaması gerekiyorsa bunun için if yazmak yerine Should().NotBeNull() kullanılır.)

Test Kodu = Uygulama Kodu

  • Uygulama kodu refactor edildiği gibi test kodu da yeniden düzenlenmeli (refactor) ve temiz olmalıdır.

  • Testlerin Dokümantasyon Olarak Test (Test as Documentation) niteliği kazanması ve bu niteliği koruması için temiz ve basit olması gerekir.

Clean Code - Birim Testleri

Testleri Temiz Tutmak

  • Uygulama kodu değişince testler de değişmelidir. Testler ne kadar kirliyse, değişmeleri de o kadar zor olur. Geliştirmelerin uzamasını testlere bağlayan geliştiriciler test yazmayı bırakırlar. Bu da hata oranın artmasına ve kodun istenmeyen şekilde gelişmesine (karmaşıklaşmasına, temizliğini yitirmesine) neden olur. Uygulama kodu zamanla çürümeye başlar.

  • Test kodu uygulama kodu kadar önemlidir.

  • Kodumuzu esnek, bakım yapılabilir ve yeniden kullanılabilir yapan şey birim testleridir.

Testleri Temiz Yapan Şey: Okunabilirlik

  • Açıklık (clarity)

  • Basitlik (simplicity)

  • İfadenin yoğunluğu, özlüğü (daha az ifadeyle daha çok şey anlatmak.)

  • Testler için alana özel bir dil geliştirmek

Arrange (Setup)

  • Test kurulumlarının yapıldığı bölümlerde tekrar eden kurulum kodları için Niyet Belirten İsimler e sahip Creation Method lar oluşturulmalı.

  • Mock nesneler StrictMock olarak tanımlanmalı.

  • Verify edilecek mock metot çağrılarının kurulumları Verifiable() olarak işaretlenmeli.

Strict Mock

bkz. Strict Mock

Assert

Testin en önemli bölümü Assert bölümüdür. Bu bölümde, beklenen tüm davranışlar ve ilgili çıktılar kontrol edilmeli ve doğrulanmalıdır. Eksik bırakılan Assertleri olan bir testin hiç olmaması daha iyidir, çünkü kod kapsama oranının tamamlanmasına neden olur ve eksik bırakılan doğrulamalar unutulur.Kod Kapsama Oranı

  • Kod kapsamının %100 veya daha fazla olması bir şey ifade etmez. (Önemli olan beklenen tüm davranışların doğrulanmasıdır.)

  • Kod kapsama oranı %20 ise bir şey ifade eder. (Birçok testin eksik olduğunu)

Kod Tekrarı Birkaç testte tekrar eden veya bir - iki fazla satırdan uzun olan Assert tanımları Niyet Belirten İsimler_e sahip _Custom Assertion metotlarına çevrilmeli.

Beklenen Nesne (Expected Object) Assert işlemlerinde kontroller Beklenen Nesne (Expected Object) ile yapılmalı. (FluentAssertions Should().BeEquivalentTo() metodu bu amaç için uygun.)Doğrulama (Verify)

  • Sonuç döndürmeyen (void) metotların davranışları Verify ile doğrulanmalı.

  • Doğrulanacak mock metot çağrıları Verify() metodu ile doğrulanmalı.

Yardımcı Metotlar (Helper Method)

  • Yardımcı metotlar:

    • Niyet belirten isimlere sahip olmalıdır.

    • Test edilebilirler. (ve edilmelidirler.)

    • Yeniden kullanılabilirler.

  • Creation Method ve Custom Assertion gibi metotlar testlerde kullanılan yardımcı metotlardır.

  • Yardımcı setup metotları aşağıdaki tiplerde olabilir:

    • Creation Method: Nesne oluşturmak için kullanılır.

    • Parameterized Creation Method: Farklı koşulları oluşturabilmek için kullanılacak değerlerin parametre olarak geçirildiği nesne oluşturma metotlarıdır.

    • Anonymous Creation Method: Nesne değerlerinin önemli olmadığı, sadece nesnenin herhangi bir örneğini oluşturup döndüren nesne oluşturma metotlarıdır.

Yardımcı Metotların Organizasyonu

  • Bu metotlar sadece belli bir sınıfın test fixture'ında kullanılıyorsa:

    • o sınıfın içinde private olarak tanımlanabilir

    • o sınıfın dosyasında ayrı bir sınıf olarak tanımlanabilir.

    • Test projesinde aşağıdaki gibi bir dizin yapısıyla yönetilebilir. (Bu seçenek önerilir.)

      • Helpers/SetupHelpers

      • Helpers/AssertHelpers

  • Yardımcı metotların testleri de yukarıda önerilen bir dizin yapısıyla yönetilebilir.

    • HelperTests/SetupHelperTests

    • HelperTests/AssertHelperTests

Örnek Test (Pseudo-Code)

[Test]
public void MethodName_Condition_Behaviour()
{
    //Arrange
    SetupFooForCondition();

    //Act
    var result = sut.DoSomething();

    //Assert
    AssertExpectedBehaviourForCondition();
}

Clean Code - Birim Testleri

Testlerin sahip olması beklenen özellikler: F.I.R.S.T.

  • Fast

    • Testler hızlı çalışmalı. Hızlı olmazsa çalıştırmazsın.

    • Sorunları önceden göremezsin. Mikro geribildirim şansını kaçırırsın.

    • Kodu temizlemek için özgür hissetmezsin, çünkü kodu düzenlerken testleri sık sık çalıştırıp her adımda yeni durumu doğrulaman gerekir. Kodu temizlemediğin için kod çürür.

  • Independent

    • Testler birbirlerinden bağımsız olmalı. Çalışma sıraları veya ortak kullandığı veriler (örneğin kurulum verileri) sonuçlarını etkilememeli.

  • Repeatable

    • Ortamdan bağımsız olarak çalıştırılabilmeli, tekrar edilebilmeli.

  • Self-Validating

    • Boolean bir sonucu olmalı. Kendini doğrulamalı.

    • Geçmeli veya geçmemeli.

  • Timely

    • Doğru zamanda yazılmalı. (Uygulama kodundan hemen önce)

    • Uygulama kodundan sonra yazarsan uygulama kodunun test edilmesinin zor olduğunu görebilirsin.

    • Uygulama kodunu test edilebilir olarak tasarlamamış olabilirsin.

Sonuç: Testlerin çürümesine izin verirsen uygulama kodu da çürür. Testleri temiz tutmak gerekir.

One Bad Attribute

Bir nesnenin geçerlilik kontrolleri yapıldığında sadece bir özelliğinin geçersiz olma durumları test edilebilir. One Bad Attribute bu durumlarda kullanılması önerilen bir pratiktir.

  • Önce nesne geçerli olarak oluşturulur.

  • Geçerli olmaması istenen özellik geçersiz hale getirilir.

  • Nesne test edilir.

Birçok özelliğinin ayrı ayrı geçerlilik kontrolleri yapılacak nesnelerde kullanışlı bir çözüm sunar. Kurulum metodu olarak sadece geçerli nesne oluşturma metodu kullanılır ve kod tekrarı oluşmaz.

Last updated