Kamusal her şeyi saplayan ve alay eden birim testlerinin bir noktası var mı?


58

Birim yaparken "uygun" bir yol sınamak, yani her kamu çağrısını engellemek ve önceden ayarlanmış değerleri veya alayları döndürmek, aslında hiçbir şeyi sınamadığımı hissediyorum. Kelimenin tam anlamıyla koduma bakıyorum ve genel yöntemlerimle mantık akışına dayanan örnekler oluşturuyorum. Ve uygulama her değiştiğinde, gerçekten yararlı bir şey yaptığımı hissetmediğimden (bu orta veya uzun vadede olabilir) hissetmeden, tekrar tekrar bu testleri değiştirmem gerekiyor. Ayrıca entegrasyon testleri yapıyorum (mutlu olmayan yollar dahil) ve artan test sürelerini gerçekten umursamıyorum. Bunlarla, gerçekte regresyonları test ediyormuşum gibi hissediyorum, çünkü çoklu yakaladılar, tüm bu birim testler bana kamu yöntemimin uygulamasının değiştiğini gösteriyor, zaten bildiğim kadarıyla.

Ünite testi çok geniş bir konudur ve burada bir şey anlamayan biri olduğumu hissediyorum. Birim testine karşı entegrasyon testinin belirleyici avantajı nedir (genel giderler hariç)?



1
Ayrıca bakınız "
Alay

Yanıtlar:


37

Birim yaparken "uygun" bir yol sınamak, yani her kamu çağrısını engellemek ve önceden ayarlanmış değerleri veya alayları döndürmek, aslında hiçbir şeyi sınamadığımı hissediyorum. Kelimenin tam anlamıyla koduma bakıyorum ve genel yöntemlerimle mantık akışına dayanan örnekler oluşturuyorum.

Bu, test ettiğiniz yöntem gibi bazı diğer sınıf örneklerine ihtiyaç duyar (alay etmeniz gereken) ve kendi başına birkaç yöntemi çağırır.

Bu kod türünün, ana hatlarıyla belirttiğiniz sebeplerden dolayı, birimin test edilmesi gerçekten zordur.

Yararlı bulduğum şey, bu sınıfları ikiye bölmek:

  1. Gerçek "iş mantığı" olan sınıflar. Bunlar, diğer sınıflara çok az çağrı yapıyor veya hiç çağrı yapmıyor ve test edilmesi kolay (değer (ler) in-value out).
  2. Harici sistemler ile arayüz oluşturan sınıflar (dosyalar, veritabanı vb.). Bunlar harici sistemi sarar ve ihtiyaçlarınız için uygun bir arayüz sağlar.
  3. "Her şeyi birbirine bağlayan" sınıflar

O zaman sınıf 1'den ünite testi kolaydır, çünkü sadece değerleri kabul eder ve sonuç verir. Daha karmaşık durumlarda, bu sınıfların kendi başlarına çağrıları yapmaları gerekebilir, ancak yalnızca 2. sınıfları çağırırlar (ve doğrudan örneğin bir veritabanı işlevini çağırmazlar) ve 2. sınıfların alayları kolaydır (çünkü yalnızca İhtiyacınız olan sarılmış sistemin parçalarını gösterin).

2. ve 3. sınıflar genellikle anlamlı bir şekilde test edilemez (çünkü kendi başlarına yararlı bir şey yapmazlar, sadece "tutkal" kodlarıdır). OTOH, bu sınıflar nispeten basit (ve az) olma eğilimindedir, bu yüzden entegrasyon testleriyle yeterince örtülmelidirler.


Bir örnek

Bir sınıf

Bir veritabanından fiyat alan, bazı indirimler uygulayan ve ardından veritabanını güncelleyen bir sınıfınız olduğunu varsayalım.

Bunların hepsini bir sınıfta yaşıyorsanız, takılması zor olan DB işlevlerini çağırmanız gerekir. Sözde kodda:

1 select price from database
2 perform price calculation, possibly fetching parameters from database
3 update price in database

Her üç adımda da DB erişimi gerekir, bu nedenle kod veya DB yapısı değişirse kırılması muhtemel olan pek çok (karmaşık) alaycı gerekir.

Ayrılmak

Üç sınıfa ayrılırsınız: PriceCalculation, PriceRepository, App.

PriceCalculation yalnızca gerçek hesaplamayı yapar ve gereken değerleri sağlar. Uygulama her şeyi birbirine bağlar:

App:
fetch price data from PriceRepository
call PriceCalculation with input values
call PriceRepository to update prices

Bu şekilde:

  • PriceCalculation, "iş mantığını" kapsar. Test etmesi kolaydır çünkü kendi başına hiçbir şey ifade etmez.
  • PriceRepository sahte bir veritabanı ayarlayarak ve okuma ve güncelleme çağrılarını test ederek sözde birim test edilebilir. Çok az mantığı var, bu yüzden az sayıda kodepat var, bu yüzden bu testlerin çoğuna ihtiyacınız yok.
  • Yapıştırıcı kod olduğu için uygulama anlamlı bir şekilde test edilemez. Ancak, bu da çok basittir, bu nedenle entegrasyon testi yeterli olacaktır. Daha sonra App çok karmaşık hale gelirse, daha fazla "iş mantığı" dersi verirsiniz.

Son olarak, PriceCalculation'ın kendi veritabanı aramalarını yapması gerektiği ortaya çıkabilir. Örneğin, yalnızca PriceCalculation hangi verinin gereksinim duyduğunu bildiğinden, Uygulama tarafından önceden getirilemez. Daha sonra, PriceCalculation'ın ihtiyaçlarına göre uyarlanmış bir PriceRepository örneğini (veya bazı diğer depo sınıflarını) geçebilirsiniz. Daha sonra bu sınıfın alay edilmesi gerekecek, ancak PriceRepository'nin arayüzü basit, çünkü bu basit olacak PriceRepository.getPrice(articleNo, contractType). En önemlisi, PriceRepository'nin arayüzü PriceCalculation'ı veritabanından ayırır, bu nedenle DB şemasındaki veya veri organizasyonundaki değişikliklerin arayüzünü değiştirmesi ve bu nedenle alayları kırması muhtemel değildir.


5
Her şeyi test eden birimin noktasını göremediğimi sanıyordum, teşekkürler
enthrops

4
Ben sadece tip 3 sınıflarının az olduğunu söylerken katılmıyorum, kodumun çoğunun tip 3 olduğunu ve neredeyse hiç iş mantığı olmadığını hissediyorum. Demek istediğim bu: stackoverflow.com/questions/38496185/…
Rodrigo Ruiz

27

Birim testine karşı entegrasyon testinin belirleyici avantajı nedir?

Bu yanlış bir ikilik.

Birim testi ve entegrasyon testi iki benzer fakat farklı amaca hizmet eder. Birim testinin amacı, yöntemlerin çalıştığından emin olmaktır. Pratik açıdan, birim testleri, kodun birim testleri tarafından belirtilen sözleşmeyi yerine getirdiğinden emin olun . Bu, birim sınamalarının tasarlanma biçiminde açıktır: kodun ne yapması gerektiğini özellikle belirtir ve kodun bunu yaptığını iddia eder.

Entegrasyon testleri farklı. Entegrasyon testleri, yazılım bileşenleri arasındaki etkileşimi kullanır. Tüm testlerini geçen ve hala etkileşime girmedikleri için entegrasyon testlerinde başarısız olan yazılım bileşenlerine sahip olabilirsiniz.

Bununla birlikte, ünite testlerinde belirgin bir avantaj varsa, şudur: ünite testlerinin kurulması çok daha kolaydır ve entegrasyon testlerinden çok daha az zaman ve çaba gerektirir. Doğru kullanıldığında, birim testleri "test edilebilir" kodun geliştirilmesini teşvik eder, bu da nihai sonucun daha güvenilir, anlaşılması ve bakımı daha kolay olacağı anlamına gelir. Test edilebilir kod, uyumlu bir API gibi, tekrarlanabilir davranış gibi belirli özelliklere sahiptir ve kolay anlaşılan sonuçları döndürür.

Entegrasyon testleri daha zor ve daha pahalıdır, çünkü sık sık alaycı, karmaşık kurulum ve zor iddialara ihtiyaç duyarsınız. Sistem entegrasyonunun en üst seviyesinde, bir kullanıcı arabiriminde insan etkileşimini simüle etmeye çalıştığınızı hayal edin. Tüm yazılım sistemleri bu tür bir otomasyona ayrılmıştır. Ve peşinde olduğumuz otomasyon; insan testleri tekrarlanabilir değildir ve otomatik testlerde olduğu gibi ölçeklendirilmez.

Son olarak, entegrasyon testi kod kapsamı konusunda hiçbir garanti vermez. Entegrasyon testlerinizle kaç kod döngüsünün, koşulun ve dalın kombinasyonunu test ediyorsunuz? Gerçekten biliyor musun? Size ne kadar kod kapsamına sahip olduğunuzu ve kodunuzun döngüsel karmaşıklığının ne olduğunu söyleyen, birim testleri ve test altındaki yöntemlerle kullanabileceğiniz araçlar vardır. Fakat sadece ünite testlerinin yaşadığı yöntem düzeyinde gerçekten iyi çalışıyorlar.


Testleriniz her yeniden ateşlenici değişiyorsa, bu farklı bir sorun. Birim testlerinin, yazılımınızın ne yaptığını belgelemek, bunun olduğunu kanıtlamak ve daha sonra altta yatan uygulamayı yeniden düzenlemek istediğinizde tekrar yaptığını kanıtlamak için yapılması gerekiyor . API'niz değişirse veya sistem tasarımındaki değişime göre değişiklik yapmak için yöntemlere ihtiyacınız varsa, olması gereken budur. Çok fazla olursa , önce kodunuzu yazmadan önce testlerinizi yazmayı düşünün. Bu sizi genel mimari hakkında düşünmeye zorlar ve önceden kurulmuş olan API ile kod yazmanıza izin verir.

Çok fazla zaman harcıyorsanız, önemsiz kodlar için birim testleri yazıyorsanız

public string SomeProperty { get; set; }

o zaman yaklaşımını tekrar gözden geçirmelisin. Birim testinin davranışı test etmesi gerekiyor ve yukarıdaki kod satırında davranış yok. Bununla birlikte, bir yerde kodunuzda bir bağımlılık yarattınız, çünkü bu özellik neredeyse kesinlikle kodunuzda başka bir yere yönlendirilecek. Bunu yapmak yerine, gerekli özelliği parametre olarak kabul eden yöntemleri yazın:

public string SomeMethod(string someProperty);

Artık, yönteminizin kendisinin dışındaki bir şeye bağımlılığı yok ve artık tamamen kendi kendine yeten olduğundan daha test edilebilir. Verilmiş, bunu her zaman yapamayacaksınız, ancak kodunuzu daha test edilebilir olma yönünde hareket ettiriyor ve bu kez gerçek davranış için bir birim testi yazıyorsunuz .


2
Ünite testi ve entegrasyon testi sunucusunun farklı hedeflerinin olduğunu biliyorum, ancak ünite testlerinin yaptığı tüm genel çağrıları saplayıp alay ediyorsanız, ünite testlerinin ne kadar yararlı olduğunu hala anlamadım. Eğer taslaklar ve alaylar için olmasaydı 'kod, ünite testlerinde belirtilen sözleşmeyi yerine getirir'; benim birim testleri tam anlamıyla mantığın test ettiğim yöntemlerin içindeki yansımalarıdır. Siz (I) gerçekten hiçbir şeyi test etmiyor, sadece kodunuza bakıyor ve onu testlere dönüştürüyorsunuz. Otomatikleştirme zorluğu ve kod kapsamı konusunda, şu an Rails yapıyorum ve bunların ikisi de iyi halledildi.
13'te enthrops

2
Testleriniz sadece yöntem mantığının bir yansımasıysa, yanlış yapıyorsunuzdur. Birim testleriniz esas olarak metoda bir değer vermeli, bir geri dönüş değeri kabul etmeli ve bu geri dönüş değerinin ne olması gerektiği hakkında bir iddiada bulunmalıdır. Bunu yapmak için mantık gerekmez.
Robert Harvey,

2
Mantıklı ama yine de diğer tüm genel çağrıları (db, bazı 'globals'lar, şu anki kullanıcı durumu vb. Gibi) engellemeli ve yöntem mantığını izleyen test koduyla bitmelidir.
enthrops

1
Bu nedenle, birim testlerinin çoğunlukla “girdiler kümesi -> beklenen sonuçlar kümesi” olduğunu doğrulayan türden yalıtılmış testler için olduğunu düşünüyorum.
13'te enthrops

1
Çok sayıda birim ve entegrasyon testi oluşturma konusundaki deneyimim (bu testlerde kullanılan gelişmiş alaycılık, entegrasyon testi ve kod kapsamı araçlarından bahsetmiyorum), iddialarınızın çoğuyla çelişiyor: 1) "Ünite testinin amacı, kod ne gerekiyorsa yapar ": aynısı entegrasyon testi için de geçerlidir (hatta dahası); 2) "birim testlerinin ayarlanması çok daha kolay": hayır, öyle değiller (oldukça sık, kolay olan entegrasyon testleri); 3) "Doğru kullanıldığında, birim testleri" test edilebilir "kodun geliştirilmesini teşvik eder: entegrasyon testleriyle aynıdır; (devam ediyor)
Rogério

4

Alaylarla yapılan birim testleri, sınıfın uygulanmasının doğru olduğundan emin olmak içindir. Test ettiğiniz kodun bağımlılıklarının genel arayüzleriyle alay ediyorsunuz. Bu şekilde sınıfın dışındaki her şey üzerinde kontrol sahibi olursunuz ve başarısız bir testin diğer nesnelerden birinde değil sınıfın içindeki bir şey yüzünden olduğundan emin olursunuz.

Ayrıca, uygulamanın değil, testin yapıldığı sınıfın davranışını da test ediyorsunuz. Kodu yeniden değerlendirirseniz (yeni dahili yöntemler yaratma vb.), Birim testleri başarısız olmamalıdır. Ancak, genel yöntemin ne yaptığını değiştiriyorsanız, davranışları değiştirdiğiniz için testler kesinlikle başarısız olmalıdır.

Ayrıca, kodu yazdıktan sonra testleri yazıyormuş gibi görünüyorsunuz, bunun yerine önce testleri yazmayı deneyin. Sınıfın sahip olması gereken davranışları ana hatlarıyla belirtmeyi deneyin ve ardından testleri geçmek için minimum miktarda kod yazmayı deneyin.

Hem ünite testi hem de entegrasyon testi, kodunuzun kalitesini sağlamak için faydalıdır. Birim testleri, her bir bileşeni yalıtılmış olarak inceler. Entegrasyon testleri, tüm bileşenlerin doğru şekilde etkileşmesini sağlar. Test takımımda her iki türün de olmasını istiyorum.

Birim testler gelişimimde bana yardımcı oldu çünkü bir kerede uygulamanın bir parçasına odaklanabiliyorum. Henüz yapmadığım bileşenleri alay etmek. Ayrıca, mantıktaki bulduğum hataları (ünite testlerinde bile) belgelendirdikleri için regresyon için mükemmeldir.

GÜNCELLEME

Yalnızca yöntemlerin çağrıldığından emin olan bir sınama oluşturmak, aslında yöntemlerin çağrıldığından emin olduğunuzdan emin olabilir. Özellikle önce testlerinizi yazıyorsanız, olması gereken yöntemlerin bir kontrol listesi vardır. Bu kod hemen hemen işlemsel olduğu için, yöntemlerin çağrılmasından başka bir kontrol yapmanıza gerek kalmaz. Gelecekte değişiklik için kodu koruyorsunuz. Diğerlerinden önce bir yöntemi çağırmanız gerektiğinde. Veya, ilk yöntem bir istisna atsa bile, her zaman bir yöntemin çağrıldığı bir yöntemdir.

Bu yöntemin testi hiçbir zaman değişmeyebilir veya yalnızca yöntemleri değiştirirken değişebilir. Bu neden kötü bir şey? Testlerin kullanılmasının güçlendirilmesine yardımcı olur. Kodu değiştirdikten sonra bir testi düzeltmeniz gerekirse, testleri kodla değiştirme alışkanlığınız olur.


Ve eğer bir yöntem özel bir şey demezse, birim test etmenin bir anlamı yoktur, doğru mu?
13:13 enthrops

Metot özel ise, açıkça test etmiyorsunuz, genel arayüz üzerinden test edilmelidir. Davranışın doğru olduğundan emin olmak için tüm genel yöntemler test edilmelidir.
Schleis

Hayır, eğer bir genel yöntem özel bir şey demezse, bu genel yöntemi sınamak mantıklı mıdır?
enthrops

Evet. Yöntem bir şey yapmıyor mu? Bu yüzden test edilmelidir. Test açısından, özel bir şey kullanıp kullanmadığını bilmiyorum. Sadece A girişini sağlarsam, B çıkışını almam gerektiğini biliyorum.
Schleis

Ah evet, yöntem bir şey yapar ve bir şey diğer kamu yöntemlerine (ve sadece buna) çağırır. Böylece, 'doğru' bir şekilde yaptığınız testte, çağrıları bazı geri dönüş değerleri ile engelleyin ve ardından mesaj beklentilerini ayarlayın. Bu durumda ne gibi testler yapıyorsunuz? Doğru aramalar yapıldı mı? Peki, bu yöntemi yazdın ve ona bakıp tam olarak ne yaptığını görebiliyorsun. Birim testinin 'girdi -> çıktı' gibi kullanılması öngörülen izole edilmiş yöntemler için daha uygun olduğunu düşünüyorum, bu nedenle birkaç örnek oluşturabilir ve yeniden denemek için regresyon testi yapabilirsiniz.
enthrops

3

Benzer bir soru yaşıyordum - bileşen testlerinin gücünü bulana kadar. Kısacası, varsayılan olarak alay etmemeniz ancak gerçek nesneler kullanmanız (ideal olarak bağımlılık enjeksiyonu yoluyla) dışında ünite testleriyle aynıdırlar.

Bu şekilde, iyi bir kod kapsamasıyla hızlı bir şekilde sağlam testler oluşturabilirsiniz. Sahte cihazlarınızı her zaman güncellemenize gerek yok. % 100 alay ile birim testlerinden biraz daha az kesin olabilir, ancak tasarruf ettiğiniz zaman ve para bunun için telafi eder. Gerçekten alaycı ya da demirbaş kullanmanız gereken tek şey depolama arka uçları ya da dış hizmetlerdir.

Aslında, aşırı alay karşıtı bir kalıptır: TDD Anti-Kalıpları ve Alaylar kötüdür .


0

Operasyon zaten bir cevabı işaretlese de, buraya sadece 2 kuruş ekliyorum.

Birim testine karşı entegrasyon testinin belirleyici avantajı nedir (genel giderler hariç)?

Ve ayrıca cevap olarak

Birim yaparken "uygun" bir yol sınamak, yani her kamu çağrısını engellemek ve önceden ayarlanmış değerleri veya alayları döndürmek, aslında hiçbir şeyi sınamadığımı hissediyorum.

OP'nin istediği tam olarak değil, yardımcı olabilir:

Birim Testleri çalışıyor ama hala hata var mı?

Test takımları konusundaki deneyimimden, Ünite Testlerinin her zaman bir sınıfın en temel yöntem seviyesinde işlevselliğini test etmek olduğunu anlıyorum . Kanımca , kamuya açık, özel veya içsel her yöntem özel bir birim testini hakediyor. Son deneyimlerimde bile, diğer küçük özel yöntemleri çağıran ortak bir yöntemim vardı. Yani, iki yaklaşım vardı:

  1. özel yöntem için bir birim testi oluşturmayın.
  2. özel bir yöntem için Birim Testleri hazırlayın.

Mantıksal olarak düşünürseniz, özel bir yönteme sahip olmanın amacı şudur: ana ortak yöntem çok büyüyor veya dağınık oluyor. Bunu çözmek için Akıllıca yeniden toparlanın ve özel kamu yöntemlerini ayırmayı hak eden küçük kod bölümleri oluşturun; Bu özel yöntemin daha sonra tekrar kullanılabileceğini akılda tutarak reddedersiniz. Bu özel yönteme bağlı olarak başka hiçbir kamu yönteminin olmadığı ancak geleceği bilen durumlar olabilir.


Özel metodun başka birçok kamu metodu tarafından tekrar kullanıldığı durumlarda.

Öyleyse, yaklaşım 1'i seçseydim, çoğaltılmış Ünite testlerini yapardım ve karmaşık yöntem olurdu, çünkü her bir kamu yöntemi dalı ve özel yöntem için Ünite Testi sayısı vardı.

Yaklaşım 2'yi seçmiş olsaydım: birim testleri için yazılan kod nispeten daha az olurdu ve testi çok daha kolay olurdu.


Özel yöntemin tekrar kullanılmadığı durumlara bakılırsa Bu yöntem için ayrı bir birim testi yazmanın bir anlamı yoktur.

Olarak gelince Entegrasyon Testleri endişe, bunlar kapsamlı ve yüksek düzeyde daha olma eğilimindedir. Size bir girdi verildiğinde, tüm sınıflarınızın bu son karara varması gerektiğini söyleyeceklerdir. Entegrasyon testinin faydası hakkında daha fazla bilgi edinmek için lütfen belirtilen bağlantıya bakınız.

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.