Birim testleriniz ne kadar derin?


88

TDD hakkında bulduğum şey, testlerinizi ayarlamanın zaman alması ve doğal olarak tembel olduğum için her zaman mümkün olduğunca az kod yazmak istiyorum. Yaptığım ilk şey, kurucumun tüm özellikleri ayarladığını test etmek, ancak bu aşırı mı?

Sorum, size birim testleri hangi ayrıntı düzeyinde yazıyorsunuz?

..ve çok fazla test etme durumu var mı?

Yanıtlar:


221

Testler için değil, işe yarayan kod için ödeme alıyorum, bu yüzden felsefem, belirli bir güven seviyesine ulaşmak için mümkün olduğunca az test yapmaktır (Bu güven seviyesinin endüstri standartlarına kıyasla yüksek olduğundan şüpheleniyorum, ancak bu sadece kibirli olabilir) . Genelde bir tür hata yapmazsam (bir yapıcıda yanlış değişkenleri ayarlamak gibi), bunu test etmem. Test hatalarını anlamaya meyilliyim, bu yüzden karmaşık koşullu mantığım olduğunda daha dikkatli oluyorum. Bir takım üzerinde kod yazarken, toplu olarak yanlış yapma eğiliminde olduğumuz kodu dikkatlice test etmek için stratejimi değiştiriyorum.

Farklı insanların bu felsefeye dayalı olarak farklı test stratejileri olacaktır, ancak testlerin kodlamanın iç döngüsüne en iyi şekilde nasıl uyabileceğine dair olgunlaşmamış bir anlayış göz önüne alındığında bu bana mantıklı geliyor. Bundan on ya da yirmi yıl sonra, hangi testlerin yazılacağına, hangi testlerin yazılmayacağına ve farkı nasıl söyleyeceğimize dair daha evrensel bir teoriye sahip olacağız. Bu arada, deneyler sırayla görünüyor.


40
Dünya Kent Beck'in bunu söyleyeceğini düşünmüyor! Kent Beck'in yapacağı şeyin bu olduğunu düşündükleri için görev bilinciyle% 100 kapsama peşinde koşan geliştiriciler ordusu var! Birçok kişiye, XP kitabınızda, Test First'e her zaman dini olarak bağlı kalmadığınızı söylediğinizi söyledim. Ama ben de şaşırdım.
Charlie Flowers

6
Aslında katılmıyorum çünkü bir geliştiricinin ürettiği kod kendisine ait değil ve bir sonraki sprint başka biri onu değiştirecek ve sizin "bilmediğinizi bilmediğiniz" hataları işleyecek. Ayrıca TDD önce testleri düşünürsünüz. Öyleyse, kodun bir bölümünü test edeceğinizi varsayarak TDD yaparsanız, yanlış yapıyorsunuzdur
Ricardo Rodrigues

2
Kapsamla ilgilenmiyorum. Bay Beck'in başarısız bir teste yanıt olarak yazılmayan kodu ne sıklıkla işlediğiyle çok ilgileniyorum.
sheldonh

1
@RicardoRodrigues, başkalarının daha sonra yazacağı kodu kapsayacak şekilde testler yazamazsınız. Bu onların sorumluluğu.
Kief

2
Yazdığım bu değil, dikkatlice okuyun; Kendi kodunuzun yalnızca bir kısmını kapsayacak şekilde testler yazarsanız, "hata yapmadığını bildiğiniz" kısımları açıkta bırakırsanız ve bu kısımlar değişirse ve uygun testler yapılmazsa, orada bir sorununuz olduğunu yazdım. ve bu hiç de TDD değil.
Ricardo Rodrigues

20

Bozulmasını beklediğiniz şeyler ve uç durumlar için birim testleri yazın. Bundan sonra, hata için düzeltmeyi yazmadan önce, hata raporları geldikçe test senaryoları eklenmelidir. Geliştirici daha sonra şunlardan emin olabilir:

  1. Hata düzeltildi;
  2. Böcek yeniden ortaya çıkmayacak.

Ekteki yoruma göre - Eğer belirli bir sınıfta zamanla çok sayıda hata keşfedilirse, birim testleri yazmaya yönelik bu yaklaşım sorunlara neden olabilir. Muhtemelen takdir yetkisinin yardımcı olduğu yer burasıdır - yalnızca yeniden oluşması muhtemel hatalar için veya yeniden oluşmalarının ciddi sorunlara neden olacağı yerlerde birim testleri eklemek. Birim testlerinde entegrasyon testinin bir ölçüsünün bu senaryolarda yardımcı olabileceğini buldum - daha yüksek kod yollarını test etmek, daha düşük kod yollarını kapsayabilir.


Yazdığım böcek miktarı ile bu bir anti model haline gelebilir. Bazı şeylerin bozulduğu kod üzerinde yapılan yüzlerce test ile bu, testlerinizin okunamaz hale geldiği ve bu testleri yeniden yazma zamanı geldiğinde bir ek yük haline gelebileceği anlamına gelebilir.
Johnno Nolan

@JohnNolan: Test okunabilirliği o kadar önemli mi? IMHO, en azından bu hataya özgü regresyon testleri için değil. Testleri sık sık yeniden yazıyorsanız, çok düşük bir seviyede test ediyor olabilirsiniz - ideal olarak, uygulamalarınız değişse bile arayüzleriniz nispeten kararlı kalmalıdır ve arayüz seviyesinde test etmelisiniz (gerçi gerçek dünyanın çoğu zaman olmadığını fark etsem de. böyle ...: - /) Arayüzleriniz büyük bir şekilde değişirse, bu hataya özgü testlerin çoğunu veya tamamını yeniden yazmak yerine atmayı tercih ederim.
j_random_hacker

@j_random_hacker Evet, elbette okunabilirlik önemlidir. Testler bir tür dokümantasyondur ve üretim kodu kadar önemlidir. Büyük değişiklikler için hurda testlerinin iyi bir şey (tm) olduğuna ve testlerin arayüz düzeyinde yapılması gerektiğine katılıyorum.
Johnno Nolan

19

Her şey olabildiğince basit olmalı, ancak daha basit olmamalıdır. - A. Einstein

TDD ile ilgili en yanlış anlaşılan şeylerden biri, içindeki ilk kelimedir. Ölçek. Bu yüzden BDD ortaya çıktı. Çünkü insanlar ilk D'nin önemli olan Driven olduğunu gerçekten anlamadılar. Hepimiz Testler hakkında biraz fazla ve biraz da tasarımın yönlendirilmesi hakkında düşünme eğilimindeyiz. Ve sanırım bu, sorunuza belirsiz bir cevap, ancak gerçekte test ettiğiniz şey yerine muhtemelen kodunuzu nasıl kullanacağınızı düşünmelisiniz; Bu, Kapsam aracının size yardımcı olabileceği bir şeydir. Tasarım çok daha büyük ve daha sorunlu bir konu.


Evet, belirsiz ... Bu, bir kurucunun kısmi davranış olmadığı anlamına mı geliyor, onu test etmemeliyiz. Ama MyClass.DoSomething () 'i test etmeliyim?
Johnno Nolan

Şey, şuna bağlıdır: P ... eski kodu test etmeye çalışırken bir yapı testi genellikle iyi bir başlangıçtır. Ancak, sıfırdan bir şey tasarlamaya başlarken, muhtemelen (çoğu durumda) bir inşaat testini dışarıda bırakırdım.
kitofr

Geliştirme odaklı, tasarım odaklı değil. Yani, çalışan bir temel alın, işlevselliği doğrulamak için testler yazın, geliştirme ile ilerleyin. Neredeyse her zaman testlerimi, bazı kodları ilk kez çarpanlara ayırmadan hemen önce yazarım.
Evan Plaice

Son D'nin, Tasarım'ın insanların unuttuğu, dolayısıyla odağını kaybettiği kelime olduğunu söyleyebilirim. Test odaklı tasarımda, başarısız testlere yanıt olarak kod yazarsınız. Test odaklı tasarım yapıyorsanız, sonuçta ne kadar test edilmemiş kod elde edersiniz?
sheldonh

15

"Her şeyi" test etmeyi önerenler için: aşağıdaki gibi bir yöntemi "tam olarak test etmenin" farkında olun :int square(int x) yaygın dillerde ve tipik ortamlarda yaklaşık 4 milyar test senaryosu gerektirdiğini anlayın.

Aslında, bu daha da kötü: Bir yöntem void setX(int newX)de yükümlüdür değil dışında başka üyelerinin değerlerini değiştirmek için x- Bunu test ediyoruz obj.y, obj.zbütün çağrıldıktan sonra değişmeden kalır vs. obj.setX(42);?

Yalnızca "her şeyin" bir alt kümesini test etmek pratiktir. Bunu kabul ettiğinizde, inanılmaz derecede basit davranışları test etmemeyi düşünmek daha lezzetli hale gelir. Her programcı, hata konumlarının olasılık dağılımına sahiptir; Akıllı yaklaşım, enerjinizi, hata olasılığının yüksek olduğunu tahmin ettiğiniz bölgeleri test etmeye odaklamaktır.


9

Klasik cevap "kırılabilecek her şeyi test et" dir. Bunu, set veya get dışında hiçbir şey yapmayan ayarlayıcıları ve alıcıları test etmenin muhtemelen çok fazla test olduğu, zaman ayırmaya gerek olmadığı şeklinde yorumluyorum. IDE'niz bunları sizin için yazmadıkça, siz de yazabilirsiniz.

Senin yapıcı Eğer değil ayar özellikleri sonradan hatalara yol açabilir, o zaman set overkill değil olduklarını test.


yup ve bu, birçok özelliğe ve birçok oluşturucuya sahip bir sınıf için bir bağdır.
Johnno Nolan

Bir problem ne kadar önemsizse (bir üyeyi sıfıra başlatmayı unutmak gibi), hata ayıklamak için o kadar fazla zaman alır.
Lev

5

Yazacağım sınıfların varsayımlarını kapsayan testler yazıyorum. Testler gereksinimleri zorlar. Esasen, örneğin x asla 3 olamazsa, bu gereksinimi karşılayan bir test olduğundan emin olacağım.

Değişmez bir şekilde, bir durumu kapsayan bir test yazmazsam, daha sonra "insan" testi sırasında ortaya çıkacaktır. O zaman kesinlikle bir tane yazacağım, ama onları erken yakalamayı tercih ederim. Bence asıl mesele testin sıkıcı (belki) ama gerekli olmasıdır. Tamamlanacak kadar test yazıyorum ama daha fazlası değil.


5

Şimdi basit testleri atlamakla ilgili problemin bir kısmı, gelecekte yeniden düzenleme bu basit özelliği birçok mantıkla çok karmaşık hale getirebilir. Bence en iyi fikir, modül gereksinimlerini doğrulamak için Testleri kullanabilmenizdir. X'i geçtiğinizde Y'yi geri almanız gerekiyorsa, o zaman test etmek istediğiniz şey budur. Daha sonra kodu daha sonra değiştirdiğinizde, X'in size Y verdiğini doğrulayabilir ve daha sonra bu gereksinim eklendiğinde A'nın size B'yi vermesi için bir test ekleyebilirsiniz.

İlk geliştirme yazma testleri sırasında harcadığım sürenin birinci veya ikinci hata düzeltmesinde karşılığını aldığını gördüm. 3 aydır bakmadığınız kodu alma ve düzeltmenizin tüm durumları kapsadığından ve "muhtemelen" hiçbir şeyi bozmayacağından makul ölçüde emin olma yeteneği çok değerlidir. Ayrıca birim testlerinin, yığın izlemenin çok ötesinde hataları önceliklendirmeye yardımcı olacağını göreceksiniz. Uygulamanın ayrı parçalarının nasıl çalıştığını ve başarısız olduğunu görmek, neden bir bütün olarak çalıştıklarına veya başarısız olduklarına dair büyük bir içgörü sağlar.


4

Çoğu durumda, orada mantık varsa, test edin derim. Bu, özellikle mülkte birden fazla şey ayarlandığında oluşturucular ve özellikleri içerir.

Çok fazla test konusunda tartışmalı. Bazıları her şeyin sağlamlık açısından test edilmesi gerektiğini söyler, diğerleri ise verimli test için sadece kırılabilecek şeylerin (yani mantık) test edilmesi gerektiğini söyler.

Sadece kişisel deneyimlerimden, ikinci kampa daha çok eğilirdim, ama eğer biri her şeyi test etmeye karar verseydi, bunun çok fazla olduğunu söylemezdim ... belki benim için biraz abartılı, ama onlar için çok fazla değil.

Yani, Hayır - genel anlamda "çok fazla" test etme diye bir şey olmadığını söyleyebilirim, sadece bireyler için.


3

Test Güdümlü Geliştirme, tüm testleriniz başarılı olduğunda kodlamayı bırakmanız anlamına gelir.

Bir mülk için testiniz yoksa, neden onu uygulamalısınız? "Yasadışı" bir atama durumunda beklenen davranışı test etmez / tanımlamazsanız, özellik ne yapmalıdır?

Bu nedenle, bir sınıfın sergilemesi gereken her davranışı test etmek için kesinlikle varım. "İlkel" özellikler dahil.

Bu testi kolaylaştırmak TestFixtureiçin, değeri ayarlamak / almak için uzantı noktaları sağlayan ve geçerli ve geçersiz değerlerin listelerini alan ve mülkün doğru çalışıp çalışmadığını kontrol etmek için tek bir testi olan basit bir NUnit oluşturdum . Tek bir özelliği test etmek şu şekilde görünebilir:

[TestFixture]
public class Test_MyObject_SomeProperty : PropertyTest<int>
{

    private MyObject obj = null;

    public override void SetUp() { obj = new MyObject(); }
    public override void TearDown() { obj = null; }

    public override int Get() { return obj.SomeProperty; }
    public override Set(int value) { obj.SomeProperty = value; }

    public override IEnumerable<int> SomeValidValues() { return new List() { 1,3,5,7 }; }
    public override IEnumerable<int> SomeInvalidValues() { return new List() { 2,4,6 }; }

}

Lambdalar ve nitelikler kullanılarak bu daha derli toplu yazılabilir. MBUnit'in bunun gibi şeyler için bazı yerel desteğe sahip olduğunu anlıyorum. Önemli olan nokta, yukarıdaki kodun mülkün amacını yakalamasıdır.

Not: Muhtemelen PropertyTest'in nesnedeki diğer özelliklerin değişmediğini kontrol etmenin bir yolu da olmalıdır . Hmm .. çizim tahtasına geri dönelim.


MbUnit ile ilgili bir sunuya gittim. Harika görünüyor.
Johnno Nolan

Ama David, sana sormama izin ver: Kent Beck'in yukarıdaki cevabına şaşırdın mı? Cevabı, yaklaşımınızı yeniden düşünmeniz gerekip gerekmediğini merak ediyor mu? Tabii ki kimsenin "tepeden cevap" aldığı için değil. Ancak Kent, ilk önce testin temel savunucularından biri olarak düşünülüyor. Düşünceleriniz için Penny!
Charlie Flowers

@Charly: Kent'in tepkisi çok pragmatik. Çeşitli kaynaklardan gelen kodları entegre edeceğim bir proje üzerinde "sadece" çalışıyorum ve çok yüksek bir güven seviyesi sağlamak istiyorum .
David Schmitt

Bununla birlikte, test edilen koddan daha basit testler yaptırmak için çabalıyorum ve bu düzeyde ayrıntı ancak tüm oluşturucuların, modüllerin, iş kurallarının ve doğrulayıcıların bir araya geldiği entegrasyon testlerinde buna değebilir.
David Schmitt

1

Mümkün olan maksimum kapsama ulaşmak için birim testi yapıyorum. Bir koda ulaşamazsam, kapsam mümkün olduğu kadar dolu olana kadar yeniden düzenleme yaparım

Kör edici yazma testini bitirdikten sonra, genellikle her hatayı yeniden üreten bir test senaryosu yazarım

Kod testi ile entegrasyon testi arasında ayrım yapmaya alışkınım. Entegrasyon testi sırasında (bunlar aynı zamanda birim testidir, ancak bileşen grupları üzerindedir, dolayısıyla birim testi tam olarak ne içindir) doğru bir şekilde uygulanacak gereksinimleri test edeceğim.


1

Bu yüzden programımı testler yazarak ne kadar çok kullanırsam, testin ayrıntı düzeyi hakkında o kadar az endişeleniyorum. Geriye dönüp baktığımda, davranışı doğrulama hedefime ulaşmak için mümkün olan en basit şeyi yapıyorum gibi görünüyor . Bu, kodumun istediğimi yaptığına dair bir güven katmanı oluşturduğum anlamına gelir, ancak bu, kodumun hatasız olduğunun mutlak garantisi olarak değerlendirilmez. Doğru dengenin standart davranışı ve belki de bir veya iki uç durumu test etmek olduğunu hissediyorum, ardından tasarımımın bir sonraki bölümüne geçiyorum.

Bunun tüm hataları kapsamayacağını ve bunları yakalamak için diğer geleneksel test yöntemlerini kullanmayacağını kabul ediyorum.


0

Genelde işe yaraması gerektiğini bildiğim girdi ve çıktılarla küçük başlarım. Ardından, hataları düzelttikçe, düzelttiğim şeylerin test edilmesini sağlamak için daha fazla test ekliyorum. Organik ve benim için iyi çalışıyor.

Çok fazla test edebilir misin? Muhtemelen, ancak genel olarak ihtiyatlı davranmak muhtemelen daha iyidir, ancak bu, uygulamanızın ne kadar kritik olduğuna bağlı olacaktır.


0

Sanırım iş mantığınızın "özündeki" her şeyi test etmeniz gerekiyor. Getter ve Setter de kabul etmek istemeyebileceğiniz negatif değeri veya boş değeri kabul edebilir. Zamanınız varsa (her zaman patronunuza bağlıdır), diğer iş mantığını ve bu nesneleri çağıran tüm denetleyicileri test etmek iyidir (birim testinden entegrasyon testine yavaşça geçersiniz).


0

Yan etkisi olmayan basit ayarlayıcı / alıcı yöntemlerini birim test etmiyorum. Ama diğer herkese açık yöntemleri test ediyorum. Algoritmalarımdaki tüm sınır koşulları için testler oluşturmaya ve birim testlerimin kapsamını kontrol etmeye çalışıyorum.

Çok iş var ama bence buna değer. Bir hata ayıklayıcıda kod yazmak yerine kod yazmayı (hatta test kodunu) tercih ederim. Kod oluşturma-dağıtma-hata ayıklama döngüsünü çok zaman alıcı buluyorum ve yapıma entegre ettiğim birim testleri ne kadar kapsamlı olursa, o kod oluşturma-dağıtma-hata ayıklama döngüsünden geçerken o kadar az zaman harcıyorum.

Neden mimariyi kodladığınızı da söylemediniz. Ama Java ben kullanım için Maven 2 , JUnit , DbUnit , cobertura , & EasyMock .


Hangisinin oldukça dilden bağımsız bir soru olduğunu söylemedim.
Johnno Nolan

TDD'de birim testi, yalnızca kodu yazarken sizi kapsamaz, aynı zamanda kodunuzu miras alan kişiye karşı korur ve sonra alıcı içindeki bir değeri biçimlendirmenin mantıklı olduğunu düşünür!
Paxic

0

Hakkında ne kadar çok okursam, bazı birim testlerinin tıpkı kalıplara benzediğini düşünüyorum: Yetersiz dil kokusu.

Önemsiz toplayıcınızın gerçekten doğru değeri döndürüp döndürmediğini test etmeniz gerektiğinde, bunun nedeni alıcı adını ve üye değişken adını birbirine karıştırabilmenizdir. Ruby'nin 'attr_reader: name' adını girin ve bu artık olamaz. Sadece java'da mümkün değil.

Eğer sizin alıcı hiç nontrivial alır hala sonra bunun için bir test ekleyebilirsiniz.


Bir alıcıyı test etmenin önemsiz olduğuna katılıyorum. Ancak bunu bir kurucu içinde ayarlamayı unutacak kadar aptal olabilirim. Bu nedenle bir teste ihtiyaç vardır. Soruyu sorduğumdan beri düşüncelerim değişti. Cevabımı görün stackoverflow.com/questions/153234/how-deep-are-your-unit-tests/…
Johnno Nolan

1
Aslında, bir şekilde, birim testlerinin bir bütün olarak bir dil probleminin kokusu olduğunu iddia ediyorum. Eyfel gibi sözleşmeleri destekleyen diller (yöntemlerde ön / son koşullar) yine de bazı birim testlerine ihtiyaç duyar, ancak daha azına ihtiyaç duyarlar. Pratikte, basit sözleşmeler bile hataları bulmayı gerçekten kolaylaştırır: bir yöntemin sözleşmesi bozulduğunda, hata genellikle bu yöntemdedir.
Damien Pollet

@Damien: Belki de birim testleri ve sözleşmeler kılık değiştirmiş olarak gerçekten aynı şeydir? Demek istediğim, sözleşmeleri "destekleyen" bir dil, temelde, diğer kod parçacıklarından önce ve sonra (isteğe bağlı olarak) yürütülen kod parçacıkları - testler - yazmayı kolaylaştırıyor, doğru mu? Dilbilgisi yeterince basitse, sözleşmeleri yerel olarak desteklemeyen bir dil, bir ön işlemci yazarak onları desteklemek için kolayca genişletilebilir, değil mi? Yoksa bir yaklaşımın (sözleşmeler veya birim testleri) diğerinin yapamadığı ve yapabileceği bazı şeyler var mı?
j_random_hacker

0

Sizi endişelendiren kaynak kodunu test edin.

Hata yapmadığınız sürece, kendinizden çok emin olduğunuz kod bölümlerini test etmek yararlı değildir.

Bir hatayı ilk ve son kez düzeltmek için hata düzeltmelerini test edin.

Bilgi oluşturabilmeniz için belirsiz kod bölümlerinin güvenini kazanmak için test edin.

Mevcut özellikleri bozmamak için ağır ve orta düzeyde yeniden düzenlemeden önce test edin.


0

Bu cevap, kritikliği / önemi nedeniyle birim testi yapmak istediğinizi bildiğiniz belirli bir yöntem için kaç birim test kullanacağınızı bulmak için daha fazladır. McCabe'nin Temel Yol Testi tekniğini kullanarak , basit "ifade kapsamı" veya "şube kapsamı" na kıyasla niceliksel olarak daha iyi kod kapsamı güvenine sahip olmak için aşağıdakileri yapabilirsiniz:

  1. Birim testi yapmak istediğiniz yönteminizin Siklomatik Karmaşıklık değerini belirleyin (örneğin Visual Studio 2010 Ultimate bunu sizin için statik analiz araçlarıyla hesaplayabilir; aksi takdirde, akış grafiği yöntemi - http://users.csc ile elle hesaplayabilirsiniz . calpoly.edu/~jdalbey/206/Lectures/BasisPathTutorial/index.html )
  2. Yönteminiz boyunca akan bağımsız yolların temel kümesini listeleyin - akış grafiği örneği için yukarıdaki bağlantıya bakın
  3. 2. adımda belirlenen her bağımsız temel yol için birim testleri hazırlayın

Bunu her yöntem için yapacak mısınız? Ciddi anlamda?
Kristopher Johnson
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.