Yararlı bir birim testinin ne olduğunu belirlemek


46

Phpunit'in dökümanlarından geçiyorum ve aşağıdaki alıntıya rastladım:

Her zaman daha fazla test yazabilirsiniz. Ancak, hızlı bir şekilde hayal edebileceğiniz testlerin sadece bir kısmının gerçekten yararlı olduğunu göreceksiniz. İstediğiniz şey, çalışması gerektiğini düşündüğünüz halde başarısız olan testler veya başarısız olması gerektiğini düşündüğünüz halde başarılı olan testler yazmak. Bunu düşünmenin bir başka yolu maliyet / fayda açısındandır. Bilgi ile size geri ödeyecek testleri yazmak istiyorsunuz. --Erich Gamma

Merak etti beni. Birim testinin maliyet / fayda ile ilgili alıntıda belirtilenlerin yanı sıra, bir testi diğerinden daha kullanışlı kılan şeyleri nasıl belirlersiniz. Hangi kod için birim testini oluşturduğunuza karar vermeyi nasıl düşünüyorsunuz? Bunu soruyorum çünkü bu alıntılardan bir diğeri de şöyle dedi:

Öyleyse testle ilgili değilse, neyle ilgili? Bu, denemek için yarı horoz kaçmadan önce ne yapmaya çalıştığınızı bulmakla ilgili. Kısa, net ve açık bir şekilde davranış şeklinin küçük bir kısmını belirleyen bir özellik yazıyorsunuz. Bu kadar basit. Bu testler yazdığın anlamına mı geliyor? Hayır. Bu, kodunuzun ne yapması gerektiğinin özelliklerini yazdığınız anlamına gelir. Bu, kodunuzun davranışını önceden belirlediğiniz anlamına gelir. Ama zamanın çok ilerisinde değil. Aslında, kodu yazmadan hemen önce en iyisidir, çünkü o zaman elde edeceğiniz kadar bilginiz var. Aferin TDD gibi, her seferinde küçük bir artışla çalışıyorsunuz ... bir seferde küçük bir davranış yönü belirliyor ve ardından uyguluyorsunuz. Bunun tamamen davranış belirtme ile ilgili olduğunu ve test yazmamakla ilgili olduğunu anladığınızda, bakış açınız değişiyor. Birdenbire, üretim sınıflarınızın her biri için bir Test sınıfına sahip olma fikri saçma bir şekilde sınırlayıcıdır. Ve her bir yönteminizi kendi test yöntemiyle (1-1 ilişki içinde) test etme düşüncesi gülünç olacaktır. --Dave Asteller

Bunun önemli kısmı

* Ve her bir yönteminizi kendi test yöntemiyle (1-1 ilişki içinde) test etme düşüncesi gülünç olacaktır. *

Öyleyse, her yöntem için bir test oluşturmak 'gülünç' ise, testleri ne için / ne zaman seçtiniz?


5
Bu iyi bir soru, ama ben bir programlama dilinden bağımsız bir soru olan şey - neden onu php olarak etiketlediniz?

İşte hangi birim testlerini yazmam gerektiği ve otomatik testler için hangi alanların önemli olduğu konusunda bana iyi bir yön veren bazı güzel makaleler. - blog.stevensanderson.com/2009/11/04/… - blog.stevensanderson.com/2009/08/24/… - ayende.com/blog/4218/scenario-driven-tests
Kane

Yanıtlar:


26

Yöntem başına kaç test?

Teorik ve son derece pratik olmayan maksimum, N-Path karmaşıklığıdır (testlerin tümünün kod boyunca farklı yolları kapsadığını varsayın); Asgari BİR! Genel yöntem başına , uygulama ayrıntılarını test etmez, yalnızca bir sınıfın dış davranışlarını test eder (değerleri döndürür ve diğer nesneleri çağırır).

Alıntı yapıyorsun:

* Ve her bir yönteminizi kendi test yöntemiyle (1-1 ilişki içinde) test etme düşüncesi gülünç olacaktır. *

ve sonra sormak:

Öyleyse, her yöntem için bir test oluşturmak 'gülünç' ise, testleri ne için / ne zaman seçtiniz?

Ama bence buradaki yazarı yanlış anladın:

Fikri one test methodbaşına one method in the class to testyazarı "gülünç" olarak adlandırdığı şeydir.

(En azından benim için) Mesele 'daha az' değil, 'daha fazla'

Bu yüzden onu anladığım gibi tekrar etmeme izin ver:

Ve her bir yönteminizi SADECE BİR YÖNTEM (1-1 ilişkide kendi test yöntemi) ile test etme düşüncesi gülünç olacaktır.

Teklifinizi tekrar alıntı yapmak için:

Tamamen davranış belirleme ve sınama yazmakla ilgili olmadığını fark ettiğinizde, bakış açınız değişiyor.


Eğer TDD pratik zaman sanmıyorum :

Bir yöntemim var calculateX($a, $b);ve bu testCalculcateXyöntem hakkında her şeyi test eden bir test gerekiyor .

TDD'nin size söylediği şey, kodunuzun neyi sevmesi gerektiği hakkında düşünmenizdir :

İki değerden daha büyük olanı hesaplamam gerekiyor ( ilk test durumu! ) Ancak eğer $ a sıfırdan küçükse bir hata üretmeli ( ikinci test durumu! ) Ve $ b sıfırdan küçükse .... Üçüncü test durumu! ) vb.


Davranışları test etmek istiyorsun, bağlam olmadan sadece tek metodları değil.

Bu şekilde kodunuz için bir dokümantasyon olan bir test paketi alırsınız ve GERÇEKTEN ne yapması beklendiğini açıklar, belki de neden :)


Hangi kod için birim testini oluşturduğunuza karar vermeyi nasıl düşünüyorsunuz?

Depoda veya üretimin yakınında herhangi bir yerde biten her şey bir teste ihtiyaç duyar. Alıntılarını yazanın, yukarıda belirtmeye çalıştığım gibi aynı fikirde olmadığını düşünüyorum.

Eğer bir testiniz yoksa kodu değiştirmek zorlaşır (daha pahalı), özellikle de siz değişmediyseniz.

TDD, HER ŞEY için testlere sahip olmanızı sağlamanın bir yoludur, ancak testleri yazdığınız sürece sorun yok. Genellikle onları aynı gün yazmak, daha sonra yapmayacağınız için yardımcı olur, değil mi? :)



Yorumlara cevap:

iyi bir miktarda yöntem belirli bir bağlamda test edilemez, çünkü bunlar ya başka yöntemlere bağımlıdır ya da buna bağlıdır

Bu yöntemlerin arayabileceği üç şey var:

Diğer sınıfların kamu yöntemleri

Diğer sınıflarla alay edebiliriz, böylece orada durumu tanımladık. Bağlamın kontrolü bizde, bu yüzden sorun değil.

* Korunan veya aynı üzerine Özel yöntemler *

Bir sınıfın genel API'sinin bir parçası olmayan hiçbir şey doğrudan doğrudan sınanmaz.

Uygulamayı değil davranışı test etmek istersiniz ve bir sınıf bütün bunları büyük bir kamu yönteminde veya daha küçük korumalı yöntemlerde yaparsa uygulama denir . Testlerinize dokunmadan, bu korunan yöntemleri DEĞİŞTİRMEK isteyebilirsiniz. Çünkü, kodunuzdaki değişiklik davranışını değiştirirse testleriniz bozulur! Testlerin ne için orada, bir şeyi kırdığın zaman söylemek için :)

Aynı sınıftaki genel yöntemler

Bu çok sık olmaz, değil mi? Ve aşağıdaki örnekte olduğu gibi olursa, bununla başa çıkmanın birkaç yolu vardır:

$stuff = new Stuff();
$stuff->setBla(12);
$stuff->setFoo(14);
$stuff->execute(); 

Belirleyicilerin var olduğu ve execute method imzasının bir parçası olmadığı diğer bir konudur;)

Burada test edebileceğimiz, yanlış değerleri ayarladığımızda işlemlerin patlaması halinde gerçekleşmesidir. Yani setBlabir dize ayrı test edilebilir geçerken bir istisna atar ama biz bu iki izin verilen değerler (12 & 14) şu bir test durumu daha (herhangi bir nedenle) birlikte çalışarak bilmediğimiz testi istiyorum.

Eğer "iyi" bir test paketi istiyorsanız, php, belki (!) 'De, @covers Stuff::executeyalnızca bu yöntem için kod kapsamı oluşturduğunuzdan emin olmak için bir açıklama ekleyebilir ve yalnızca kurulumun yapıldığı diğer öğelerin ayrı ayrı test edilmesi gerekir (yine, bunu istiyorsun).

Yani mesele şu ki: Belki önce çevreleyen dünyalardan bazılarını yaratmanız gerekir, ancak genellikle sadece bir veya iki gerçek işlevi kapsayan anlamlı test durumları yazabilmelisiniz (ayarlayıcılar burada sayılmaz). Geri kalan eter alay edilebilir veya önce test edilebilir ve daha sonra güvenilebilir (bakınız @depends).


* Not: Soru SO'dan taşındı ve başlangıçta PHP / PHPUnit ile ilgiliydi, bu nedenle örnek kod ve referansların php dünyasından kaynaklandığını düşünüyorum, bunun phpunit diğer xUnit'ten çok farklı olmadığı için diğer dillere de uygulanabilir olduğunu düşünüyorum. test çerçeveleri.


Çok ayrıntılı ve bilgilendirici ... “Davranışları yalnızca bağlamsal olmayan tek yöntemleri değil, test etmek istiyorsunuz” dedin. Kesinlikle, makul miktarda yöntem, belirli bir bağlamda test edilemez, çünkü bunlar ya başka yöntemlere bağımlıdır ya da bağımlıdır. Bu nedenle, yararlı bir test koşulu yalnızca bağımlılar da test edildiğinde bağlamsal olacaktır? Ya da ne demek istediğinizi yanlış yorumluyorum>
zcourts

@ robinsonc494 Belki biraz daha iyi anlatacağım bir örnekte düzenleyeceğim
edorian

düzenlemeler ve örnek için teşekkürler, kesinlikle yardımcı olur. Sanırım kafamın kargaşası (buna diyebilirseniz), "davranış" için test hakkında bir şeyler okusam da, bir şekilde sadece doğal olarak (belki de?) Uygulamaya odaklanan test vakaları hakkında düşündüm.
zcourts,

@ robinsonc494 Belki şu şekilde düşünün: Eter birine yumruk attığında, yumruk attığında, polisi ara ya da kaçar. Bu davranış Kişinin yaptığı budur. Beyninden gelen küçük elektrik yükleriyle tetiklenen midelerini kullanması gerçek. Birisinin tepkisini test etmek istiyorsanız, onu yumruklayın ve beklediğiniz gibi davranıp davranmadığını görün. Onu bir beyin tarayıcısına koyup dürtülerin midye yollu olup olmadığını göremezsin. Bazıları hemen hemen sınıflar için geçerli;)
edorian

3
Sanırım test vakalarının nasıl yazılacağına gerçekten yardım eden TDD'nin en iyi örneği, Bob Amca Martin tarafından Bowling Oyunu Katasıydı. slideshare.net/lalitkale/bowling-game-kata-by-robert-c-martin
Amy Anuszewski

2

Test ve Ünite Testi aynı şey değildir. Ünite Testi, genel olarak Testin çok önemli ve ilginç bir altkümesidir. Birim Testinin odağının bize bu tür testler hakkında yukarıdaki alıntıları bir şekilde çelişecek şekilde düşündürdüğünü iddia ediyorum.

Öncelikle, TDD'yi ve hatta DTH'yi takip edersek (yani, yakın bir uyum içinde geliştirin ve test edin), tasarımımızı doğru yapmaya odaklandığımız bir yazı olarak kullanıyoruz. Köşe kasaları düşünerek ve buna göre testler yazarak, böceklerin ilk başta girmesini önleriz, bu yüzden aslında geçmeyi umduğumuz bir test yazarız (Tamam, TDD'nin başlangıcında, başarısız olurlar, ama bu sadece bir sipariş eseridir) Kod bitti, onlardan geçmelerini bekliyoruz ve çoğu, çünkü kod hakkında düşündünüz.

İkinci olarak, Birim Testleri, yeniden ateşlendiğimizde gerçekten kendi başlarına ortaya çıkıyor. Uygulamamızı değiştiriyoruz ancak cevapların aynı kalmasını bekliyoruz - Birim Testi arayüz sözleşmemizi ihlal etmemize karşı korumamızdır. Yani yine bir tane daha testlerin geçmesini bekliyoruz.

Bu, muhtemelen kararlı olan ortak arabirimimiz için, her ortak yöntemin test edildiğini görebilmemiz için net izlenebilirliğe ihtiyaç duyduğumuz anlamına gelir.

Açık sorunuzu yanıtlamak için: Genel arayüz için Birim Test değeri var

Yanıt yorumunda düzenlenmiş:

Özel yöntemlerin test edilmesi? Evet, yapmalıyız, ancak bir şeyi test etmememiz gerekirse, o zaman uzlaşacağım yer burasıdır. Sonuçta, eğer kamu yöntemleri işe yarıyorsa, o zaman özel meselelerdeki bu böcekler bu kadar önemli olabilir mi? Pragmatik olarak, karmaşası özel olaylarda ortaya çıkma eğilimindedir, genel arayüzünüzü korumak için çok çalışırsınız, ancak bağımlı olduğunuz şeyler değişse özel şeyler değişebilir. Bir noktada, iç testlerin sürdürülmesinin çok çaba olduğunu söyleyebiliriz. Bu çaba harcanıyor mu?


Yani sadece ne dediğinizi anladığımdan emin olmak için: Test ederken, genel arayüzü doğru şekilde test etmeye odaklanın mı? Bunun doğru olduğunu varsayarsak ... hataları test etmediğiniz özel yöntemlerde / arayüzlerde hata bırakma olasılığı daha yüksek değil, denenmemiş "özel" arayüzdeki bazı zor böcekler muhtemelen test edildiğinde teste neden olabilir Gerçekten başarısız olmalıydı. Öyle düşünmekte yanlış mıyım?
zcourts

Kod kapsamını kullanarak, genel yöntemlerinizi test ederken özel yöntemlerinizdeki kodun yürütülmediğini anlayabilirsiniz. Genel yöntemleriniz tamamen kapsanıyorsa, ele geçirilen herhangi bir özel yöntem açıkça kullanılmaz ve kaldırılabilir. Değilse, genel yöntemleriniz için daha fazla test yapmanız gerekir.
David Harkness

2

Birim testleri, daha büyük bir test stratejisinin parçası olmalıdır. Ne tür testler yazacağımı seçerken bu ilkeleri takip ediyorum:

  • Uçtan uca testler yazmaya odaklanın. Test başına birim testlerden daha fazla kod kapsıyorsunuz ve bu yüzden paranın karşılığını daha fazla test alıyorsunuz. Bunları sisteminizin bir bütün olarak ekmek ve tereyağı otomatik olarak doğrulamasını sağlayın.

  • Karmaşık mantık külçelerinin etrafındaki ünite testleri yazmaya başlayın. Birim testler, uçtan uca testlerin hata ayıklamanın zor olacağı ya da yeterli kod kapsamı için yazmanın yanlış olduğu durumlarda ağırlıklarına değer.

  • Her iki tür testi de yazmak için , test ettiğiniz API'nin kararlı olmasını bekleyin . Hem uygulamanızı hem de testlerinizi yeniden değerlendirmek zorunda kalmak istemezsiniz.

Rob Ashton, bu konuyla ilgili, yukarıdaki ilkeleri açıkça ifade etmek için yoğun şekilde çektiğim güzel bir makaleye sahiptir .


+1 - Tüm puanlarınızla (veya makalenin puanlarıyla) mutlaka aynı fikirde değilim, ancak kabul ettiğim yerde, körce yapılırsa (TDD yaklaşımı) çoğu birim testinin yararsız olduğu. Ancak, ünite testleri yaparak neye zaman harcamanın değerli olduğuna karar vermek konusunda akıllıysanız, son derece değerlidir. Özellikle alt sistem düzeyinde otomatikleştirilmiş testler olmak üzere daha yüksek seviye testler yazma pahasına çok daha fazla para kazanmanız konusunda tamamen katılıyorum. Uçtan uca otomatik testlerle ilgili sorun, herhangi bir boyut / karmaşıklığa sahipse, bir sistem için tamamen pratik olmasa da zor olmalarıdır.
Dunk

0

İşe yarayacak gibi görünen birim testlerine farklı bir yaklaşım izlemeye meyilliyim. Bir ünite testini "Bazı davranışları test etme" olarak düşünmek yerine, "kodumun izlemesi gereken bir şartname" olarak düşünüyorum. Bu şekilde, temel olarak bir nesnenin belirli bir şekilde davranması gerektiğini beyan edebilir ve programınızın herhangi bir yerinde, bunun oldukça hatasız olacağından oldukça emin olabileceğinizi varsayarsınız.

Genel bir API yazıyorsanız, bu çok değerlidir. Bununla birlikte, her zaman iyi bir uçtan uca entegrasyon testine ihtiyaç duyacaksınız, çünkü% 100 birim test kapsamına yaklaşmak genellikle buna değmez ve birim test yöntemleri (alaycı, vb)

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.