“İyi” birim testleri nasıl yazılır?


61

Bu iş parçacığı tarafından tetiklendiğinde (yine) projelerimde birim testleri kullanmayı düşünüyorum. Birkaç poster, "Testler iyi, eğer iyi testlerse iyidir" gibi bir şey söylüyor. Şimdi sorum şu: "İyi" testler nelerdir?

Uygulamalarımda, ana bölüm sıklıkla, büyük miktarda gözlenen verilere bağlı olarak ve bu verileri modellemek için kullanılabilecek bir uyum işlevi ile sonuçlanan bir tür sayısal analizdir. Olası girdilerin ve sonuçların sayısı her vakayı test etmek için çok büyük olduğundan ve bu yöntemlerin kendileri genellikle oldukça uzunca olduğundan ve performanstan ödün vermeden kolayca yeniden değerlendirilemediğinden, bu yöntemler için testler yapmak özellikle zor bulundu. Bu tür bir yöntem için özellikle "iyi" testler ilgimi çekiyor.


8
Herhangi bir iyi birim testi yalnızca bir şeyi test etmelidir - başarısız olursa, neyin yanlış gittiğini tam olarak bilmeniz gerekir.
gablin

2
Çok miktarda veriye sahip olmanın iyi yanı, veri dosyalarını girdi olarak alabilen genel testler yazmaktır. Veri dosyaları tipik olarak hem girdi hem de beklenen sonuç içermelidir. Xunit test çerçeveleri ile anında veri örnekleri oluşturabilirsiniz - her veri örneği için bir tane.
froderik

2
@gablin "Başarısız olursa, neyin yanlış gittiğini bilmeniz gerekir", birden fazla olası başarısızlık nedeni olan testlerin, testin sonucundan nedenini belirleyebildiğiniz sürece, sorun değil mi?
user253751 9

Hiç kimse ünite testlerinin operasyonun ne kadar sürdüğünü test edebileceğini söylemedi. Kodunuzu performans göz önünde bulundurarak yeniden değerlendirebilir, birim testinin zamanın yanı sıra sonuçlara göre zaman içinde geçtiğini veya başarısız olduğunu bildirmesini de sağlayabilirsiniz.
CJ Dennis,

Yanıtlar:


52

Birim Testleri Sanatının birim testleri hakkında söyleyecekleri vardır:

Bir birim testi aşağıdaki özelliklere sahip olmalıdır:

  • Otomatik ve tekrarlanabilir olmalıdır.
  • Uygulaması kolay olmalı.
  • Yazıldıktan sonra, ileride kullanılmak üzere kalmalıdır.
  • Herkes çalıştırabilmeli.
  • Bir düğmeye basıldığında çalışmalıdır.
  • Hızlı koşmalı.

ve sonra daha sonra tamamen otomatik, güvenilir, okunaklı ve bakımı yapılabilir olduğunu ekler.

Henüz yapmadıysanız, bu kitabı okumanızı şiddetle tavsiye ederim.

Kanımca tüm bunlar çok önemli, ama son üç (güvenilir, okunaklı ve bakımı yapılabilir), özellikle de testleriniz bu üç özelliğe sahipmiş gibi, o zaman kodunuzda da genelde var.


1
Birim testini hedefleyen kapsamlı bir liste için +1 (entegrasyon veya fonksiyonel test değil)
Gary Rowe

1
Bağlantı için +1. Orada bulunacak ilginç malzeme.
Joris Meys

1
"Hızlı koş" un büyük etkileri var. Birim testlerinin, veritabanı, dosya sistemi, web servisi vb. Gibi harici kaynaklardan uzakta, ayrı bir şekilde çalışmasının nedeni budur. Bu, alay / taslaklara yol açar.
Michael Easter

1
o söylediği zaman It should run at the push of a button, bu bir birim test ya kapları (app sunucusu) (birim için test edilen) çalıştıran veya kaynak bağlantı (örneğin DB, vb dış web hizmetleri) gerektirmemelidir demek? Bir uygulamanın hangi kısımlarının test edileceği ve hangilerinin yapılmaması gerektiği konusunda kafam karıştı. Birim testlerinin DB bağlantısına ve çalışan kaplara bağlı kalmaması gerektiği ve bunun yerine belki örnekler kullandığı söylendi.
20

42

İyi bir birim testi, test ettiği işlevi yansıtmaz.

Oldukça basitleştirilmiş bir örnek olarak, ortalama iki int döndüren bir işleve sahip olduğunuzu düşünün. En kapsamlı test fonksiyonu çağırır ve sonucun ortalama olup olmadığını kontrol eder. Bu hiç mantıklı gelmiyor: test ettiğiniz işlevselliği yansıtıyorsunuz (kopyalıyorsunuz). Ana fonksiyonda bir hata yaptıysanız, aynı hatayı testte de yapacaksınız.

Başka bir deyişle, kendinizi birim testindeki ana işlevselliği çoğalttığınızı görürseniz, zamanınızı boşa harcayacağınızın bir işareti olabilir.


21
+1 Bu durumda ne yapardınız kodlanmış argümanlarla test etmek ve bilinen cevabınızı kontrol etmek.
Michael K

Bu kokuyu daha önce görmüştüm.
Paul Butcher

Ortalamaları döndüren işlev için iyi bir birim testi örneği verebilir misiniz?
VLAS

2
@VLAS testi önceden tanımlanmış değerleri, örn. Avg (1, 3) == 2, ayrıca INT_MAX, sıfırlar, negatif değerler vb. Gibi kenar durumlarını da daha önemlisi kontrol edin. Bu hatanın bir daha asla tekrar kullanılmayacağından emin olmak için test edin.
mojuba,

İlginç. Test girişlerine doğru cevapları almayı ve sınava tabi olan kodla aynı hatayı yapmamayı nasıl önerirsiniz?
Timo

10

İyi birim testleri aslında çalıştırılabilir formda şartnamedir:

  1. Kullanım durumlarına karşılık gelen kodun davranışını betimler.
  2. teknik köşe kasalarını kapsar (boş geçilirse ne olur) - bir köşe kasası için bir test yoksa, davranış tanımlanmaz.
  3. test edilen kodun özellikten uzaklaşması durumunda kes

Temel olarak önce API'yi yazdıktan sonra fiili uygulamadan sonra Test-Driven-Development'ın kütüphane rutinleri için çok uygun olduğunu gördüm.


7

TDD için "iyi" , müşterinin istediği test özelliklerini test eder ; özellikler mutlaka işlevlere karşılık gelmez ve test senaryoları geliştirici tarafından bir boşlukta oluşturulmamalıdır

Senin durumunda - Tahmin ediyorum - 'özellik' fit işlevinin giriş verilerini belirli bir hata toleransı içinde modellemesidir. Ne yaptığınız hakkında hiçbir fikrim olmadığı için, bir şey yapıyorum; umarım analgoustur.

Örnek hikaye:

[X-Wing Pilot] olarak [% 0.0001'den fazla uyum hatası yok] istiyorum [hedefleme bilgisayarı bir kutu kanyonda tam hızda hareket ederken Death Star'ın egzoz portuna varabilir]

Öyleyse gidip pilotlarla konuşun (ve eğer duyarlıysa, hedef bilgisayarla). İlk önce 'normal' olandan, sonra anormal olandan bahsedin. Bu senaryoda neyin önemli olduğunu, neyin ortak olduğunu, neyin olası olmadığını ve neyin mümkün olduğunu keşfedersiniz.

Diyelim ki normalde yedi kanal telemetri verisi üzerinde yarım saniyelik bir pencereye sahip olacaksınız: hız, adım, yuvarlanma, yalpalama, hedef vektör, hedef boyut ve hedef hız ve bu değerlerin sabit veya doğrusal olarak değişeceği. Anormal olarak daha az kanalınız olabilir ve / veya değerler hızla değişiyor olabilir. Yani birlikte , bazı testler ile geldin:

//Scenario 1 - can you hit the side of a barn?
Given:
    all 7 channels with no dropouts for the full half-second window,
When:
    speed is zero
    and target velocity is zero
    and all other values are constant,
Then:
    the error coefficient must be zero

//Scenario 2 - can you hit a turtle?
Given:
    all 7 channels with no dropouts for the full half-second window,
When:
    speed is zero
    and target velocity is less than c
    and all other values are constant,
Then:
    the error coefficient must be less than 0.0000000001/ns

...

//Scenario 42 - death blossom
Given:
    all 7 channels with 30% dropout and a 0.05 second sampling window
When:
    speed is zero
    and position is within enemy cluster
    and all targets are stationary
Then:
    the error coefficient must be less than 0.000001/ns for each target

Şimdi, hikayede açıklanan belirli durum için bir senaryo olmadığını fark etmiş olabilirsiniz. Müşteri ve diğer paydaşlarla konuştuktan sonra, orijinal hikayedeki bu amaç sadece varsayımsal bir örnekti. Gerçek testler sonraki tartışmadan çıktı. Bu olabilir. Hikaye yeniden yazılmalı, ancak böyle olmak zorunda değildir (çünkü hikaye sadece müşteriyle sohbet etmek için bir yer tutucudır).


5

Yalnızca minimum giriş sayısını (olası 1 veya 0) ve birkaç standart durumda içeren bir test seti gibi köşe durumlarda için testler oluşturun. Bu birim testleri tam kabul testlerinin yerini almaz, ne de yapmamalı.


5

İnsanların, nadiren girilen kod için sınama yazma ve sık girilen kod için sınama yazma gibi çok fazla çaba harcadıkları pek çok vaka gördüm.

Herhangi bir test yazmak için oturmadan önce yeterli kapsamı planladığınızdan emin olmak için bir tür arama grafiğine bakıyor olmalısınız.

Ek olarak, "Evet, bunu test ediyoruz" demek için test yazmaya inanmıyorum. Düşürülen ve değişmeyen bir kütüphane kullanıyorsam, belirli bir bölümünün puan alsa bile, asla değişmeyecek bir API'nin doğuştan gelenlerin çalışmasını sağlamak için testler yazmayacağım. Bir çağrı grafiği üzerinde yüksek. Sözü edilen kütüphaneyi tüketen testler (kendi kodum) bunu gösteriyor.


Ancak daha sonraki bir tarihte kütüphanede bir hata düzeltmesi olan daha yeni bir sürüm olduğunda ne olur?

@ Thorbjørn Ravn Andersen - Kütüphaneye, neyin değiştiğine ve kendi test sürecine bağlıdır. Yerine bıraktığımda çalıştığını bildiğim kod için testler yazmayacağım ve asla dokunmayacağım. Yani, güncellemeden sonra çalışırsa, aklından çıkar :) :) Tabii ki istisnalar da var.
Tim Post

kütüphanenize bağlıysanız, yapabileceğiniz en az şey, kütüphanenin gerçekten yapmasını beklediğiniz şeyi gösteren testler

... ve eğer bu değişmişse, söylenen kütüphaneyi tüketen şeyler üzerinde testler ... Üçüncü taraf kodunun içindekileri test etmeme gerek yok. Cevap, netlik için güncellendi.
Tim Post

4

TDD değil, QA'ya girdikten sonra, QA işlemi sırasında ortaya çıkan hataları üretmek için test durumları oluşturarak testlerinizi geliştirebilirsiniz. Bu, uzun vadeli desteğe girdiğinizde ve insanların istemeden eski böcekleri yeniden ortaya koyma riskini taşıyacağınız bir yere gelmeye başladığınızda özellikle değerli olabilir. Bunu yakalamak için bir test yaptırmak özellikle değerlidir.


3

Her testin sadece bir şeyi test etmesini sağlarım. Her sınava shouldDoSomething () gibi bir ad vermeye çalışıyorum. Uygulamayı değil davranışı test etmeye çalışıyorum. Sadece genel yöntemleri test ediyorum.

Genelde başarı için bir veya birkaç testim var ve sonra genel yöntem başına başarısızlık testi için bir avuç sınavım olabilir.

Maketleri çok kullanırım. İyi bir sahte çerçeve muhtemelen PowerMock gibi oldukça yardımcı olacaktır. Yine de henüz kullanmıyorum.

A sınıfı başka bir B sınıfı kullanıyorsa, X'in bir arayüzünü eklerim, böylece A doğrudan B'yi kullanmaz. Sonra mock-up XMockup oluşturabilir ve testlerimde B yerine kullanırdım. Testin yürütülmesini hızlandırmaya, test karmaşıklığını azaltmaya gerçekten yardımcı oluyor ve ayrıca A için yazdığım test sayısını azaltıyor, çünkü B'nin özellikleriyle baş etmek zorunda kalmıyorum. B.someMethod () 'i çağırmanın yan etkisi yerine.

Test kodunu da temiz tutun.

Bir veritabanı katmanı gibi bir API kullanırken, alay etmeyi mümkün kılarken alay-up komutunun mümkün olan her fırsatta bir istisna oluşturmasını sağlardım. Daha sonra testleri bir kez atmadan, bir döngüyü geçtikten sonra, her seferinde test tekrar başarılı olana kadar bir sonraki fırsatta bir istisna atarım. Symbian için mevcut hafıza testleri gibi.


2

Andry Lowry'nin zaten Roy Osherove'in birim test metriklerini gönderdiğini görüyorum; fakat hiç kimse Bob Amca'nın Temiz Kod'da (132-133) verdiği (ücretsiz) seti sunmadı. FIRST kısaltmasını kullanıyor (burada özetlerim var):

  • Hızlı (hızlı koşmalılar, bu yüzden insanlar onları çalıştırmaya aldırmayacaklar)
  • Bağımsız (testler birbirini yapmamalı veya sökmemelidir)
  • Tekrarlanabilir (tüm ortamlarda / platformlarda çalışmalıdır)
  • Kendi kendine doğrulama (tam otomatik; çıktı bir günlük dosyası değil "pass" veya "fail" olmalıdır)
  • Zamanında (ne zaman yazılmalı - test kodunu yazmadan hemen önce)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.