Tüm yöntemlerimizi test etmeli miyiz?


61

Bugün ekip arkadaşımla birim testi hakkında konuştum. Her şey bana “hey, o sınıfın sınavları nerede, sadece bir tane görüyorum?” Diye sorduğunda başladı. Tüm sınıf bir menajerdi (ya da böyle çağırmayı tercih ederseniz bir hizmet) ve neredeyse tüm yöntemler bir DAO'ya malzeme dağıtıyordu;

SomeClass getSomething(parameters) {
    return myDao.findSomethingBySomething(parameters);
}

Mantıksız (veya en azından mantık gibi basit bir yetki vermeyi düşünmüyorum) bir tür kazan, ancak çoğu durumda kullanışlı bir kazan plakasıdır (katman ayrımı vb.). Ve birim test etmem gerekip gerekmediğine dair oldukça uzun bir tartışma yaptık (DAO'yu tamamen birim test etmekten bahsetmeye değer olduğunu düşünüyorum). Başlıca argümanları TDD olmadığı (açıkçası) ve birinin bu yöntemin ne yaptığını kontrol etmek için testi görmek isteyebileceği (nasıl daha açık olabileceğini bilmiyorum) ya da gelecekte birinin değiştirmek isteyebileceği olduğu yönündeki argümanı uygulamaya koy ve ona yeni (veya daha çok "herhangi biri gibi") mantığı ekle (bu durumda birisinin bu mantığı test etmesi gerektiğini düşünüyorum ).

Bu olsa, bana düşündürdü. En yüksek test kapsamı% için çaba göstermeli miyiz? Yoksa o zaman sadece sanat uğruna bir sanat mı? Ben sadece böyle şeyleri test etmenin arkasında herhangi bir sebep görmüyorum:

  • alıcılar ve ayarlayıcılar (içlerinde gerçekten bir mantık yoksa)
  • "Genelge kodu

Açıkçası böyle bir yöntem (alaylı) için test yapmak bir dakikadan daha az zaman alır ancak sanırım bu hala zaman kaybı ve her CI için daha uzun bir milisaniye.

Her birinin (ya da olabildiğince) kod satırını neden test etmesi gerektiğine dair rasyonel / "yanıcı" olmayan sebepler var mı?


2
Hala bu soruyla ilgili fikrimi oluşturuyorum, ama işte cevabın "hayır" olduğuna karar vermiş birinin konuşması. Ian Cooper: TDD, her şey ters gitti Bu harika konuşmayı özetlemek için dışarıdan test etmeli ve yeni davranışlar değil, yeni yöntemler denemelisiniz.
Daniel Kaplan

Bu gerçekten harika bir konuşma, mutlaka görmelisiniz, birçok insan için bir göz açıcı konuşma, onu seviyorum. Ama cevabın "hayır" olmadığını düşünüyorum. "Evet, ancak dolaylı olarak". Ian Cooper, altıgen mimari hakkında konuşur ve portları dalgalandıran / inatlayan özellikleri / davranışları test eder. Bu durumda bu portlar DAO'lardır ve bu "yönetici / hizmet" yalnızca bu sınıf için ayrı bir birim testiyle değil, bazı özellikleri test eden bir "birim test" (Ian Cooper tanımındaki birim ile tamamen katılıyorum) ile test edilmiştir. etki alanınızda bu yöneticisi / hizmeti kullanan
AlfredoCasado


Sisteminize bir dereceye kadar bağlı olacaktır, orta ila yüksek güvenlik sertifikasına sahip bir sistem geliştiriyorsanız, triviallity'den bağımsız olarak tüm yöntemleri kapsamanız gerekecektir
jk.

Yanıtlar:


48

Kent Beck'in kuralına uyuyorum:

Kırılabilecek her şeyi test edin.

Tabii ki, bu bir dereceye kadar özneldir. Bana göre, önemsiz alıcılar / ayarlayıcılar ve sizinki gibi tek gömlekler genellikle buna değmez. Ama sonra tekrar, zamanımın çoğunu eski kod için birim testleri yazarak geçiriyorum, sadece güzel bir yeşil alan TDD projesi hayal ediyorum ... Bu tür projelerde kurallar farklı. Eski kodla asıl amaç, mümkün olduğu kadar az çabayla toprağı kaplamaktır; bu nedenle, birim testleri terminoloji hakkında bilgili ise, daha fazla entegrasyon testleri gibi daha yüksek seviye ve daha karmaşık olma eğilimindedir. Ve% 0'dan genel kod kapsamı almakta zorlanıyorsanız veya yalnızca% 25'in üzerine çıkarmayı başardığınızda, birim test alıcıları ve ayarlayıcıları endişelerinizin en küçüğüdür.

Bir yeşil alan TDD projesinde OTOH, bu tür yöntemler için bile testler yazmak daha doğru olabilir. Özellikle daha önce test yazdığınızdan, merak etmeye başlamadan önce "bu özel bir teste değecek mi?" Ve en azından bu testler yazmak için önemsiz ve hızlı koşuyorlar, bu yüzden her iki şekilde de önemli değil.


Ah bu teklifi tamamen unuttum! Sanırım bunu ana argümanım olarak kullanacağım çünkü açıkçası - burada ne kırabilir? Pek değil. Kırılabilecek tek şey yöntem çağırmadır ve bu gerçekleşirse, gerçekten kötü bir şey olduğu anlamına gelir. Teşekkürler!
Zenzen

5
@ Zenzen: "Burada ne kırılabilir? Gerçekten değil." - Yani yapabilirsiniz bölünürler. Sadece küçük bir yazım hatası. Ya da birileri bazı kod ekler. Veya bağımlılığı bozar. Bence Beck, ana örneğinizin kırılabilir olarak nitelendirildiğini iddia edeceğini düşünüyor. Alıcılar ve ayarlayıcılar, daha azına rağmen, kendimi bir kopyala / yapıştır hatasında yakalamış olmama rağmen, o zaman bile. Asıl soru, bir test yazmak için çok önemsiz ise, neden var bile?
pdr

1
Bunu düşünmek için harcadığınız zamanı testten geçirmiş olabilirsiniz. testi yaz derim, gri alan olarak test yazmamayacağınız zaman ayrılmayın, daha fazla kırık pencere görünecektir.
kett_chup

1
Genel deneyimim, alıcıların ve ayarlayıcıların test edilmesinin uzun vadede biraz değerli ama düşük öncelikli olduğunu ekleyeceğim. Bunun nedeni, neden şimdi bir hata bulma şansının "sıfır" olması nedeniyle, başka bir geliştiricinin üç ay içinde ("yalnızca basit bir ifade" ise) kırma şansına sahip bir şey eklemeyeceğini garanti edemezsiniz. . Bir birim testinin yapılması buna karşı koruma sağlar. Aynı zamanda, bu aşırı derecede yüksek bir öncelik değil, çünkü kısa sürede hiçbir şey bulamayacaksınız.
dclements

7
Kırılabilecek her şeyi kör bir şekilde test etmek mantıklı değil. İlk önce yüksek riskli bileşenlerin test edildiği bir strateji olması gerekir.
CodeART

12

Birkaç tür birim testi vardır:

  • Devlet bazlı. Nesnenin durumuna karşı harekete geçiyorsunuz. Örneğin ben depozito yaparım. Daha sonra dengenin artmış olup olmadığını kontrol ediyorum.
  • Getiriye dayalı değer. Geri dönüş değerine karşı hareket ediyorsun.
  • Etkileşim tabanlı. Nesnenizin başka bir nesne aradığını doğrulayın. Bu, örneğinizde yaptığınız gibi görünüyor.

İlk önce testinizi yazacak olsaydınız, bir veri erişim katmanı çağırmayı beklediğiniz gibi, daha anlamlı olurdu. Test başlangıçta başarısız olur. Daha sonra testi geçmek için üretim kodu yazacaktınız.

İdeal olarak, mantıksal kodu test etmeniz gerekir, ancak etkileşimler (diğer nesneleri çağıran nesneler) eşit derecede önemlidir. Senin durumunda, ben isterdim

  • Veri erişim katmanını, tam olarak girilmiş olan parametreyle aradığımı kontrol edin.
  • Sadece bir kere çağrıldığını kontrol et.
  • Veri erişim katmanı tarafından bana verilenleri tam olarak iade ettiğimi kontrol et. Aksi takdirde null dönebilirim.

Şu anda orada bir mantık yok, ama her zaman böyle olmayacak.

Ancak, bu yöntemde bir mantık olmayacağına ve aynı kalması muhtemel olduğundan eminseniz, veri erişim katmanını doğrudan tüketiciden çağırmayı düşünürdüm. Bunu sadece takımın geri kalanı aynı sayfadaysa yapardım. "Hey millet, etki alanı katmanını yok saymak iyidir, doğrudan veri erişim katmanını çağırmanız yeterlidir" diyerek ekibe yanlış bir mesaj göndermek istemezsiniz.

Bu yöntem için bir entegrasyon testi olsaydı, diğer bileşenleri de test etmeye konsantre olurdum. Henüz sağlam entegrasyon testleri olan bir şirket görmedim.

Bunları söyledikten sonra - her şeyi kör bir şekilde test etmem. Sıcak noktaları kurardım (yüksek karmaşıklığa ve kırılma riskine sahip parçalar). Daha sonra bu bileşenlere konsantre olurdum. Kod tabanının% 90'ının oldukça basit olduğu bir kod tabanına sahip olmanın bir anlamı yoktur ve geri kalan% 10'u sistemin temel mantığını temsil ettiği ve karmaşıklıklarından dolayı birim testlerinin kapsamına girmediği bir birim testlerle kaplanır.

Son olarak, bu yöntemi test etmenin faydası nedir? Bu işe yaramazsa sonuçları nelerdir? Onlar felaket mi? Yüksek kod kapsamı kazanmak için çaba göstermeyin. Kod kapsamı, iyi bir birim test paketi ürünü olmalıdır. Örneğin, ağaçta yürüyecek ve size bu yöntemin% 100'ünü kapsayan bir test yazabilir veya% 100'ünü de kapsayan üç ünite testi yazabilirsiniz. Aradaki fark, üç test yazarak, sadece ağacı yürümek yerine, en son durumları test etmek.


DAL'inizin sadece bir kez arandığını neden kontrol ettiniz?
Marjan Venema

9

Yazılımınızın kalitesini düşünmenin iyi bir yolu:

  1. tip kontrolü problemin bir kısmını ele alıyor.
  2. Test gerisini halleder

Kazan plakası ve önemsiz işlevler için, işini yaparken tip kontrolüne güvenebilirsiniz ve geri kalanı için test durumlarına ihtiyacınız vardır.


Tabii ki, tür kontrolü yalnızca kodunuzda belirli türler kullanıyorsanız ve derlenmiş bir dil üzerinde çalışıyorsanız ya da statik bir analiz denetiminin sık sık, örneğin CI'nin bir parçası olarak çalıştırıldığından emin olmanız durumunda işe yarar.
bdsl

6

Kanımca siklomatik karmaşıklık bir parametredir. Bir yöntem yeterince karmaşık değilse (alıcılar ve ayarlayıcılar gibi). Ünite testi gerekmez. McCabe'nin Siklomatik Karmaşıklık seviyesi 1'den büyük olmalıdır.


Bazı alıcıların veya ayarlayıcıların yan etkileri olduğunu unutmayın (çoğu durumda cesareti kırılmış ve kötü uygulama olarak kabul edilse de), bu nedenle kaynak kodunuzdaki değişiklik de onu etkileyebilir.
Andrzej Bobak 20:12

3

TDD ile yankılanan bir YES (ve birkaç istisna dışında)

Tartışmalı bir sorun değil, ancak bu soruya 'hayır' cevabını veren herhangi birinin TDD'nin temel bir kavramının eksik olduğunu iddia ediyorum.

TDD'yi izlerseniz , benim için cevabın cevabı evet . Değilse, hayır makul bir cevaptır.

TDD’deki DDD

TDD, genellikle size ana faydalara sahip olarak belirtilir.

  • Savunma
    • Kodun sağlanması davranışını değiştirebilir ancak değiştiremez .
    • Bu, yeniden yapılanmanın hiç bu kadar önemli bir uygulamasına izin vermez .
    • Bu TDD'yi kazandınız ya da almayın.
  • dizayn
    • Bir şeyin ne yapması gerektiğini, uygulamadan önce nasıl davranması gerektiğini siz belirlersiniz .
    • Bu genellikle daha bilinçli uygulama kararları anlamına gelir .
  • belgeleme
    • Test paketi şartname (gereksinimler) dokümantasyonu olarak hizmet etmelidir .
    • Bu amaçla testlerin kullanılması, dokümantasyon ve uygulamanın her zaman tutarlı bir durumda olduğu anlamına gelir - birindeki değişiklik, diğerindeki değişiklik anlamına gelir. Gereksinimleri ve tasarımları ayrı kelime dokümanlarında saklayın.

Uygulamadan ayrı sorumluluk

Programcılar olarak, nitelikleri bir anlam yükü ve alıcılar ve bir tür genel gider olarak belirleyici olarak düşünmek çok caziptir.

Ancak nitelikler bir uygulama detayıdır; düzenleyiciler ve alıcılar, programları gerçekten çalıştıran sözleşmeye bağlı arabirimlerdir.

Bir nesnenin şunu yapması gerektiğini hecelemek çok daha önemlidir

Müşterilerinin durumunu değiştirmesine izin ver

ve

Müşterilerinin durumunu sorgulamasına izin ver

o zaman bu durumun gerçekte nasıl saklandığı (hangi özelliğin en yaygın olduğu, ancak tek yol olmadığı).

Gibi bir test

(The Painter class) should store the provided colour

TDD'nin dokümantasyon kısmı için önemlidir .

Sonunda uygulamanın önemsiz (nitelik) olması ve savunma yardımı yapmaması gerçeği , testi yazarken sizin tarafınızdan bilinmemelidir.

Gidiş dönüş mühendisliği eksikliği ...

Sistem geliştirme dünyasında kilit sorunlardan biri gidiş-dönüş mühendisliği eksikliğidir 1 - bir sistemin geliştirme süreci, eserler (belgeler, kodlar) çoğunlukla tutarsız olan ayrık alt işlemlere bölünmüştür.

1 Brodie, Michael L. "John Mylopoulos: kavramsal modellemenin dikildiği tohumlar." Kavramsal Modelleme: Temeller ve Uygulamalar. Springer Berlin Heidelberg, 2009. 1-9.

... ve TDD bunu nasıl çözdü?

Öyle dokümantasyon sistemi ve onun kod özellikleri her zaman tutarlı olmasını sağlar TDD parçası.

Önce tasarım, sonra uygulayın

TDD'ye önce başarısız kabul testini, ancak daha sonra geçmelerine izin veren kodu yazın.

Üst düzey BDD içinde önce senaryolar yazıp geçtik.

Ayarlayıcıları ve alıcıyı neden dışlamalısınız?

Teoride TDD'de bir kişinin testi yazması, diğeri testi geçmek için kodu uygulamasında mükemmel bir şekilde mümkündür.

Öyleyse kendinize sorun:

Bir sınıfa yönelik sınavları yazan kişi, alıcılardan ve ayarlayıcıdan bahsetmelidir.

Alıcı ve ayarlayıcılar bir sınıfa ortak bir arayüz olduğundan, cevap açıktır ki evet , veya bir nesnenin durumunu ayarlama veya sorgulamanın bir yolu olmayacak.

Açıkçası, önce kodu yazarsanız, cevap çok net olmayabilir.

İstisnalar

Bu kuralın bazı belirgin istisnaları vardır - açık bir şekilde uygulama detayı açık olan ve açıkça sistemin tasarımının bir parçası olmayan fonksiyonlar.

Örneğin, yerel bir yöntem 'B ()':

function A() {

    // B() will be called here    

    function B() {
        ...
    }
} 

Veya buradaki özel işlev square():

class Something {
private:
    square() {...}
public:
    addAndSquare() {...}
    substractAndSquare() {...}
}

Veya public, sistem bileşeninin tasarımında yazım gerektiren bir arabirimin parçası olmayan diğer bir işlev .


1

Bir felsefi soru ile karşı karşıya kaldığınızda, sürüş gereksinimlerine geri dönün.

Amacınız rekabetçi bir maliyetle oldukça güvenilir bir yazılım üretmek mi?

Yoksa maliyeti ne olursa olsun mümkün olan en yüksek güvenilirliğe sahip bir yazılım üretmek mi?

Bir noktaya kadar, kalite ve geliştirme hız / maliyet uyumunun iki hedefi: hataları düzeltmek yerine testleri yazmak için daha az zaman harcıyorsunuz.

Ama bu noktanın ötesinde, onlar değil. Her ay geliştirici başına bir rapor edilmiş hatayı elde etmek o kadar zor değil. Bunu iki ayda bir yarıya indirmek, yalnızca bir veya iki günlük bir bütçe sunar ve bu fazladan testler muhtemelen kusur oranınızı yarı yarıya düşürmez. Yani artık basit bir kazan / kazan değil; Kusur maliyetini müşteriye göre doğrulamak zorundasınız.

Bu maliyet değişkenlik gösterecektir (ve eğer kötülük yapmak istiyorsanız, bu maliyetleri piyasadan ya da bir davadan alıp size geri getirme kabiliyetleri olacaktır). Kötü olmak istemezsiniz, bu yüzden bu maliyetleri tamamen geri sayıyorsunuz; Bazen bazı testler hala küresel olarak dünyayı varlıklarından dolayı daha fakir hale getirmektedir.

Kısacası, yolcu uçağı uçuş yazılımıyla aynı standartları kurum içi bir web sitesine kör olarak uygulamaya çalışırsanız, işiniz bitebilir veya hapis cezasına çarptırılırsınız.


0

Buna cevabınız, felsefenize bağlı (Chicago ve Londra'nın olduğuna inanıyor musunuz? Birisinin bakacağına eminim). Jüri hala en etkili yaklaşım konusunda hala bu konuda çalışmaya devam ediyor (çünkü sonuçta bu en az itici güç, düzeltmeler için harcanan zamanın en büyüğü).

Bazı yaklaşımlar sadece ortak arayüzü sınamak, diğerleri ise her işlev çağrısında her işlev sırasını sınamak der. Bol miktarda kutsal savaş yapıldı. Benim tavsiyem her iki yaklaşımı da denemektir. Bir kod birimi seçin ve X, diğeri Y gibi yapın. Birkaç aylık test ve entegrasyondan sonra geri dönün ve hangisinin sizin gereksinimlerinize daha uygun olduğunu görün.


0

Bu zor bir soru.

Açıkçası, bunun gerekli olmadığını söyleyebilirim. Olumlu ve olumsuz senaryolarda öngörüldüğü şekilde iş gereksinimlerinin işlevini güvence altına alan BDD stil birimi ve sistem seviyesi testleri yazarken daha iyi olursunuz.

Bu, eğer yönteminiz bu test durumları kapsamında değilse, o zaman neden ilk sırada yer aldığını ve gerekip gerekmediğini veya kodunuzda belgelerinize veya kullanıcı öykülerinize yansıtılmayan gizli gereksinimler olup olmadığını sorgulamanız gerekir. BDD tarzı bir test durumunda kodlanmalıdır.

Şahsen kapsama alanını% 85-95 civarında tutmayı ve hat başına mevcut birim test kapsamını garanti altına almak ve tüm kod dosyaları için bu dosyaların isabet etmemesini sağlamak için ana hatta giriş girişlerini kontrol etmeyi seviyorum.

En iyi test uygulamalarına uyulduğunu varsayarsak, bu, geliştiricilerin, sadece kapsama uğramaları için zor egzersiz kodları veya önemsiz kodlar için nasıl ilave kapsama alanı sağlamaya çalıştıklarını anlamaya çalışırken zaman harcamaya zorlamadan, birçok kapsam sağlar.


-1

Sorun, sorunun kendisidir, sistemlerinizin tüm özelliklerini test etmek için ihtiyacınız olan tüm "methdos" veya "sınıfları" test etmeniz gerekmez.

Yöntem ve sınıflar açısından düşünme yerine, özellikler / davranışlar terimlerinin anahtar düşüncesi. Elbette bir veya daha fazla özellik için destek sağlamak için bir yöntem, sonunda tüm kodlarınız test edildi, en azından kod tabanınızdaki tüm kodlar önemlidir.

Senaryonuzda, muhtemelen bu "yönetici" sınıfı gereksiz veya gereksiz ("yönetici" kelimesini içeren tüm sınıflar gibi) veya belki de değil, ancak bir uygulama detayı gibi görünüyor, muhtemelen bu sınıf bir birimi haketmiyor Test, çünkü bu sınıfın alakalı bir iş mantığı yok. Muhtemelen bazı özelliklerin çalışması için bu sınıfa ihtiyacınız var, bu özelliğin testi bu sınıfı kapsar, bu şekilde bu sınıfı yeniden değerlendirebilir ve önemli olan şeyin, özelliklerinizi hala refactordan sonra çalıştığını doğrulayan bir test yapabilirsiniz.

Yöntem sınıflarında olmayan özellikleri / davranışları düşünün, bunu yeterince tekrarlayamam.


-4

Bu olsa, bana düşündürdü. En yüksek test kapsamı% için çaba göstermeli miyiz?

Evet, ideal olarak% 100, ancak bazı şeyler test edilebilir değildir.

alıcılar ve ayarlayıcılar (içlerinde gerçekten bir mantık yoksa)

Alıcılar / Alıcılar aptalca - sadece kullanmayın. Bunun yerine, üye değişkeninizi genel bölüme koyun.

"Genelge kodu

Ortak kodu alın ve birim test edin. Bu kadar basit olmalı.

Her birinin (ya da olabildiğince) kod satırını neden test etmesi gerektiğine dair rasyonel / "yanıcı" olmayan sebepler var mı?

Bunu yapmazsanız, çok açık bazı hataları özleyebilirsiniz. Birim testleri, belirli tür böcekleri yakalamak için güvenli bir ağ gibidir ve mümkün olduğunca kullanmalısınız.

Ve son şey: İnsanların bazı "basit kodlar" için birim testleri yazarak zamanlarını boşa harcamak istemedikleri bir projedeyim, ancak daha sonra hiç yazmamaya karar verdiler. Sonunda, kodun bölümleri büyük çamur topuna dönüştü .


Bir şeyi açıklığa kavuşturalım: TDD / yazma testlerini kullanmam demek istemedim. Tam tersi. Testlerin düşünmediğim bir hata bulabileceğini biliyorum, ama burada test edilecek ne var? Sadece basitçe böyle bir yöntemin "test edilemez" birimlerinden biri olduğunu düşünüyorum. Péter Török’in dediği gibi (Kent Beck’ten alıntı yaparak) kırabilecek şeyleri denemelisiniz. Burada ne kırılabilir ki? Çok fazla değil (bu yöntemde sadece basit bir delegasyon var). Bir birim testi yazabilirim, ancak basitçe DAO ile alay edecekti ve pek çok test değil, bir iddiaya sahip olacak. Alıcılara / ayarlayıcılara gelince, bazı çerçeveler onları gerektirir.
Zenzen

1
Ayrıca, "Yaygın kod al ve birim test et. Bu kadar basit olmalı." Bununla ne demek istiyorsun? Bir servis sınıfıdır (GUI ve DAO arasındaki servis katmanında), tüm uygulama için ortaktır. Gerçekten daha genel hale getiremez (bazı parametreleri kabul ettiğinden ve DAO'da belirli bir yöntemi çağırdığından). Bunun tek nedeni, uygulamanın katmanlı mimarisine bağlı kalmaktır; böylece GUI, DAO'yu doğrudan çağırmaz.
Zenzen

20
-1 için "Alıcılar / Belirleyiciler aptaldır - yalnızca onları kullanmayın. Bunun yerine, üye değişkeninizi genel bölüme koyun." - Çok yanlış. Bu SO üzerinde birkaç kez tartışılmıştır . Her yerde genel alanların kullanılması, her yerdeki alıcıları ve ayarlayıcıları kullanmaktan bile daha kötü.
Péter Török
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.