Birim testleriyle ne test etmelisiniz?


122

Üniversiteden yeni çıktım ve önümüzdeki hafta üniversiteye başlıyorum. Birim testleri gördük, ama onları fazla kullanmadık; herkes onlardan bahsediyor, ben de belki biraz yapmalıyım diye düşündüm.

Sorun şu ki, ne test edeceğimi bilmiyorum . Ortak davayı test etmeli miyim? Kenar davası? Bir fonksiyonun yeterince kapsandığını nasıl bilebilirim?

Her zaman bir testin bir fonksiyonun belirli bir durum için işe yaradığını ispat etmesine rağmen, fonksiyonun çalıştığını ispatlamak tamamen yararsız bir duygudur.


Roy Osherove'in Blog'una bir göz atın . Videolar dahil ünite testleri hakkında birçok bilgi var. Ayrıca çok iyi olan “Birim Test Sanatı” adlı bir kitap yazdı.
İskeleler Myers

9
Neredeyse 5 yıl sonra bu konuda ne düşünüyorsunuz? Çünkü gittikçe daha fazla insanın, bugünlerde "birim test edilmemesi" gerektiğini bilmesi gerektiğini düşünüyorum. Davranış odaklı gelişim, sorduğunuz gibi sorulardan gelişti.
Remigijus Pankevičius

Yanıtlar:


121

Benim kişisel felsefem şimdiye kadar olmuştur:

  1. Yapabileceğiniz her şeyin ortak vakasını test edin. Bu, bir değişiklik yaptıktan sonra bu kodun ne zaman kırıldığını söyleyecektir (bence, otomatik birim testinin en büyük yararıdır).
  2. Muhtemelen hatalar olacağını düşündüğünüz, alışılmadık derecede karmaşık birkaç kodun son durumlarını test edin.
  3. Bir hata bulduğunuzda, düzeltmeden önce onu örtmek için bir sınama durumu yazın
  4. Birisi öldürmek için vakti olduğunda daha az kritik koda kenar testleri uygulayın.

1
Bunun için teşekkürler, OP ile aynı sorularla buraya girdim.
Stephen

5
+1, mantıksal bir API'niz olduğundan emin olmak için herhangi bir kütüphane / yardımcı program işlevinin son durumlarını da test edeceğim. Örneğin, bir boş değer geçildiğinde ne olur? boş girdi ne olacak? Bu, tasarımınızın mantıklı olmasını sağlamaya ve köşe durumu davranışını belgelemeye yardımcı olacaktır.
mikera

7
# 3, bir birim testinin nasıl yardımcı olabileceğinin gerçek bir örneği olduğu için çok katı bir cevaba benziyor. Bir kez kırılırsa, tekrar kırılabilir.
Ryan Griffith

Daha yeni başladım, testler geliştirmede çok yaratıcı değilim. Bu yüzden onları # 3 olarak kullanıyorum ve bu böceklerin bir daha asla tespit edilemeyeceğinden emin olmanızı sağlıyor.
ankush981

Cevabınız bu popüler bültende
BugHunterUK

67

Şimdiye kadar verilen cevaplar arasında hiç kimse, denklem bölünmesi ve sınır değer analizi , eldeki sorunun cevabında hayati hususlara değinmedi. Diğer cevapların tümü yararlı olsa da niteldir ancak burada nicel olmak mümkündür. @ fishtoaster, sadece test kantitatif örtüsü altında gözetleme yaparak bazı somut kılavuzlar sağlar, ancak denklik ayrıştırma ve sınır değer analizi daha iyi yapmamızı sağlar.

In denklik bölümleme , bekleneni sonuçlara göre gruplara olası tüm girdilerin dizi bölün. Bir gruptan herhangi bir giriş eşdeğer sonuçlar verecektir, bu nedenle bu tür gruplara denklik sınıfları denir . (Eşdeğer sonuçların aynı sonuç anlamına gelmediğini unutmayın .)

Basit bir örnek olarak, küçük harf ASCII karakterlerini büyük harf karakterlerine dönüştürmesi gereken bir program düşünün. Diğer karakterler kimlik dönüşümünden geçmelidir, yani değişmeden kalmalıdır. İşte denklik sınıflarına olası bir dağılımı:

| # |  Equivalence class    | Input        | Output       | # test cases |
+------------------------------------------------------------------------+
| 1 | Lowercase letter      | a - z        | A - Z        | 26           |
| 2 | Uppercase letter      | A - Z        | A - Z        | 26           |
| 3 | Non-alphabetic chars  | 0-9!@#,/"... | 0-9!@#,/"... | 42           |
| 4 | Non-printable chars   | ^C,^S,TAB... | ^C,^S,TAB... | 34           |

Son sütun, hepsini numaralandırırsanız, test senaryolarının sayısını bildirir. Teknik olarak, @ fishtoaster kuralı 1'e göre 52 test vakası içerirsiniz - yukarıda verilen ilk iki sıra için olanların tümü "ortak dava" altındadır. @ fishtoaster kuralı 2, yukarıdaki 3. ve 4. sıralardan bazılarını veya tümünü ekler. Ancak denklik bölümleme testi ile her bir denklik sınıfındaki herhangi bir test durumu yeterlidir. "A" veya "g" veya "w" seçerseniz aynı kod yolunu denersiniz. Bu nedenle, 52+ yerine toplam 4 test durumunuz var.

Sınır değer analizi hafif bir ayrıntılandırma önerir: temel olarak bir denklik sınıfının her üyesinin eşdeğer olmadığını gösterir. Yani, sınırlardaki değerler de kendi başlarına bir test vakasına layık görülmelidir. (Bunun basit bir gerekçesi, rezil teker teker hatadır !) Böylece, her bir denklik sınıfı için 3 test girişi olabilir. Yukarıdaki giriş alanına bakıldığında - ve bazı ASCII değerleri bilgisine sahipken - bu test senaryosu girişlerini bulabilirim:

| # | Input                | # test cases |
| 1 | a, w, z              | 3            |
| 2 | A, E, Z              | 3            |
| 3 | 0, 5, 9, !, @, *, ~  | 7            |
| 4 | nul, esc, space, del | 4            |

(Asıl denklik sınıfı tanımlamaları yeniden düşünmek isteyebileceğinizi öne süren 3 sınır değerden fazlasını alır almaz, ancak bu onları tekrar gözden geçirmek için geri dönmeme yetecek kadar basitti.) Bu nedenle, sınır değer analizi bize sadece Kapsamlı bir güvence ile 17 test vakası - kapsamlı test yapmak için 128 test vakasına kıyasla. (Kombinatoriklerin ayrıntılı testlerin gerçek dünyadaki herhangi bir uygulama için kolayca olanaksız olduğunu belirttiğinden bahsetmeyin!


3
+1 Testlerimi sezgisel olarak böyle yazıyorum Şimdi bir isim koyabilirim :) Bunu paylaştığın için teşekkürler.
guillaume31

+1 "nitel cevaplar yararlıdır, ancak bu mümkündür - ve tercih edilir - nicel olmak"
Jimmy Breck-McKye

Direktif "testlerimle nasıl iyi bir şekilde örtüşebilirim" ise, bunun iyi bir cevap olduğunu düşünüyorum. Bunun üzerine pragmatik bir yaklaşım bulmanın faydası olacağını düşünüyorum - her katmandaki her mantık parçasının her dalının bu şekilde ayrıntılı olarak test edilmesi gerektiği?
Kieren Johnstone

18

Muhtemelen benim fikrim çok popüler değil. Ancak birim testlerinde ekonomik olmanızı öneririm. Çok fazla birim testiniz varsa, gerçek kodlama yerine testleri koruyarak zamanınızın yarısını veya daha fazlasını harcayarak kolayca bitebilirsiniz.

Bağırsaklarınızda kötü hissettiğiniz şeyler veya çok önemli ve / veya temel olan şeyler için testler yazmanızı öneririm. IMHO birim testleri iyi mühendislik ve savunma kodlamasının yerine geçmez. Şu anda az ya da çok kullanılamaz bir proje üzerinde çalışıyorum. Gerçekten kararlıdır, ancak ateş düşürücü bir acıdır. Aslında hiç kimse bu koda bir yıl içinde dokunmamış ve dayandığı yazılım yığını 4 yaşında. Neden? Ünite testleriyle karışık olduğundan, kesin olarak: Ünite testleri ve otomatik entegrasyon testleri. (Salatalık ve benzerlerini hiç duydunuz mu?) Ve işte en iyi bölüm: Bu (henüz) kullanılamaz yazılım parçası, çalışanları test odaklı geliştirme sahnesinde öncü olan bir şirket tarafından geliştirilmiştir. : D

Yani benim önerim:

  • Temel iskeleti geliştirdikten sonra testleri yazmaya başlayın , aksi takdirde yeniden yapılandırma acı verici olabilir. Başkaları için gelişen bir geliştirici olarak, başlangıçta gereksinimleri tam olarak alamazsınız.

  • Ünite testlerinizin hızlı bir şekilde gerçekleştirilebildiğinden emin olun. Bütünleştirme testleriniz varsa (salatalık gibi), biraz daha uzun sürerse sorun olmaz. Ancak uzun süren testler eğlenceli değil, inan bana. (İnsanlar, C ++ 'ın daha az popüler olmasının nedenlerini unutuyorlar ...)

  • Bu TDD malzemesini TDD uzmanlarına bırakın.

  • Ve evet, bazen beklenmedik durumları beklediğiniz yere bağlı olarak kenar davalara, bazen de ortak davalara yoğunlaşıyorsunuz. Her zaman beklenmedik bir şey beklemeseniz de, iş akışınızı ve disiplininizi yeniden düşünmelisiniz. ;-)


2
Testlerin neden bu yazılımı yeniden yönlendirici için acı verici hale getirdiğine dair daha fazla ayrıntı verebilir misiniz?
Mike Partridge

6
Büyük +1. Yerine kuralların uygulanması test birim testlerin duvarlarını sahip herhangi bir değişiklik 2-3x gibi birçok gerektirir yapar
TheLQ

9
Kötü yazılmış üretim kodu gibi, kötü yazılmış birim testlerinin de korunması zordur. "Çok fazla ünite testi", KURU kalmama gibi görünüyor; Her test sistemin belirli bir bölümünü ele almalı / kanıtlamalıdır.
Allan

1
Her ünite testi bir şeyi kontrol etmelidir, bu nedenle çok fazla ünite testi değil, eksik testler vardır. Ünite testleriniz karmaşıksa, bu başka bir konudur.
graffic

1
-1: Bu yazının kötü yazılmış olduğunu düşünüyorum. Bahsedilen çok şey var ve hepsinin nasıl ilişki kurduğunu bilmiyorum. Cevabın amacı "ekonomik" ise, o zaman örneğinizle nasıl bir bağlantısı var? Örnek durumunuz (gerçek olsa da) kötü ünite testleri yapmış gibi görünüyor. Lütfen hangi dersleri almam gerektiğini ve nasıl ekonomik olmamda bana yardımcı olacağını açıkla. Ayrıca, dürüstçe söylüyorum, söylediğinde ne demek istediğini anlamıyorum Leave this TDD stuff to the TDD-experts.
Alexander Bird,

8

İlk önce Test Odaklı Gelişme ile test ediyorsanız, kapsama alanınız% 90 veya daha yüksek bir seviyede olacaktır, çünkü bunun için ilk önce başarısız bir ünite testi yazmadan işlevsellik eklemeyeceksiniz.

Aslında sonra testler ekliyorsanız, o zaman bir kopyasını almak yeterli tavsiye edemez Legacy Kanunu ile Etkili Çalışma tarafından Michael Feathers ve ekleme kodunuzu testler ve kodunuzu üstlenmeden yolları ikisi için bazı teknikler bakmak daha test edilebilir hale getirmek için.


Bu teminat yüzdesini nasıl hesaplarsınız? Zaten kodunuzun% 90'ını örtmek ne anlama geliyor?
zneak

2
@zneak: bunları sizin için hesaplayacak kod kapsamı araçları var. "Kod kapsamı" için hızlı bir google bunlardan birkaçını getirmelidir. Araç, testler yapılırken yürütülen kod satırlarını izler ve kapsam (lar) daki toplam kod satırlarını kapsama yüzdesini bulmak için karıştırır.
Steven Evers

-1. Soruyu cevaplamıyor:The problem is, I don't know _what_ to test
Alexander Bird

6

Teste Dayalı Geliştirme uygulamalarını izlemeye başlarsanız , süreç boyunca size rehberlik eder ve neyin test edileceğini doğal olarak bilir. Başlamak için bazı yerler:

Testler önce gelir

Testleri yazmadan önce asla kod yazmayın. Açıklama için Kırmızı-Yeşil-Refaktör-Tekrar bölümüne bakınız .

Regresyon testleri yaz

Bir hatayla karşılaştığınızda, bir test çantası yazın ve başarısız olduğundan emin olun . Arızalı bir test çantası aracılığıyla bir hatayı çoğaltamazsanız, gerçekten bulamadınız.

Kırmızı-Yeşil-Elden Geçirme-tekrarlayın

Kırmızı : Uygulamaya çalıştığınız davranış için en temel sınamayı yazarak başlayın. Bu adımı üzerinde çalıştığınız sınıfı veya işlevi kullanan bazı örnek kodlar yazarken düşünün. Derleme / sözdizimi hatası olmadığından ve başarısız olduğundan emin olun . Bu açık olmalıdır: herhangi bir kod yazmadınız, bu yüzden başarısız olmalı, değil mi? Burada öğrenilecek önemli şey, testin en az bir kez başarısız olduğunu görmediğiniz sürece, geçmesi durumunda, bazı sahte nedenlerden dolayı yaptığınız bir şeyden dolayı olduğundan emin olamayacağınızdır.

Yeşil : Testin başarılı olmasını sağlayan en basit ve aptal kodu yazın. Akıllı olmaya çalışma. Son derece belirgin bir vaka olduğunu görseniz bile, test hesaba katılırsa, bunu ele almak için kod yazmayın (ancak son durumu da unutmayın: daha sonra ihtiyacınız olacak). Buradaki fikir, yazdığınız her kod parçasının if, her try: ... except: ...birinin , her birinin bir test vakası ile doğrulanması gerektiğidir. Kodun şık, hızlı veya optimize olması gerekmez. Sadece testin geçmesini istiyorsun.

Refactor : Kodunuzu temizleyin , yöntem adlarını doğru alın. Testin hala devam edip etmediğini kontrol edin. Optimize. Testi tekrar yap.

Tekrar ediyorum : Testin kapsamadığı kenar durumunu hatırlıyorsunuz, değil mi? Yani, şimdi büyük anı. Bu durumu kapsayan bir test çantası yazın, başarısız olduğunu izleyin, bazı kodlar yazın, geçtiğini görün, refactor.

Kodunuzu test edin

Belirli bir kod parçası üzerinde çalışıyorsunuz ve bu tam olarak test etmek istediğiniz şey. Bu, kütüphane işlevlerini, standart kütüphaneyi veya derleyicinizi test etmemeniz gerektiği anlamına gelir. Ayrıca, "dünyayı" test etmekten kaçının. Bu, şunları içerir: harici web API'lerini çağırmak, bazı veritabanı yoğun şeyleri vb.


1
Zaten varolan ve (görebildiğim kadarıyla) çalışan bir kod tabanına sahip olduğumu varsayarak ne yapabilirim?
zneak

Bu (kodun nasıl yazıldığına bağlı olarak) biraz daha zor olabilir. Regresyon testleriyle başlayın (her zaman anlamlı olurlar), ardından kodun ne yaptığını anladığınızı kanıtlamak için birim testleri yazmayı deneyebilirsiniz. Yapılması gereken (görünüşte) yapılan iş miktarıyla bunalmak kolaydır, ancak: bazı testler her zaman hiçbir testten daha iyidir.
Ryszard Szopa

3
-1 Bu soru için çok iyi bir cevap olduğunu sanmıyorum . Soru TDD ile ilgili değil, birim testleri yazarken neyin test edileceğini soruyor . Bence asıl soruya iyi bir cevap TDD olmayan bir metodolojiye uygulanmalı.
Bryan Oakley

1
Dokunursanız, test edin. Ve Temiz Kod (Robert C Martin) 3. parti kod için "öğrenme testleri" yazmanızı önerir. Bu şekilde kullanmayı öğrenirsiniz ve yeni bir sürümün kullandığınız davranışı değiştirmesi durumunda testler yapılır.
Roger Willcocks

3

Birim testleri için, yapmak üzere tasarlandığı şeyi yaptığını test etmeye başlayın. Yazdığın ilk dava bu olmalı. Tasarımın bir parçası "hurdalığa girerseniz bir istisna atmalıdır" ise, bunu tasarımın bir parçası olduğu için test edin.

Bununla başla. Bu testin en temelini yapma konusunda deneyim kazandıkça, bunun yeterli olup olmadığını öğrenmeye başlayacak ve kodunuzun test edilmesi gereken diğer yönlerini görmeye başlayacaksınız.


0

Stok cevabı "kırılabilecek her şeyi test etmektir " .

Kırmak için çok basit olan ne? Veri alanları, beyin ölümü özellikli erişim sağlayıcıları ve ek olarak benzer bir boyler plakası. Başka bir şey muhtemelen bir gereksinimin tanımlanabilir bir kısmını uygular ve test edilmekten faydalanabilir.

Elbette, kilometreniz - ve çalışma ortamınızın uygulamaları - değişebilir.


Tamam. Peki hangi davaları test etmeliyim? "Normal" davası? Kenar davası?
zneak

3
Temel kural mı? Altın yolun ortasına doğru bir veya iki, kenarların hemen içinde ve hemen dışında.
Jeffrey Hantin

@JeffreyHantin Farklı bir cevapta "sınır değer analizi".
Roger Willcocks
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.