Yinelenen kod, birim testlerinde daha tolere edilebilir mi?


113

Bir süre önce birkaç ünite testini mahvetmiştim ve onları daha KURU hale getirmek için yeniden düzenledim - her testin amacı artık net değildi. Görünüşe göre testlerin okunabilirliği ve sürdürülebilirliği arasında bir denge var. Birim testlerinde yinelenen kodu bırakırsam, daha okunaklı olurlar, ancak SUT'yi değiştirirsem, yinelenen kodun her bir kopyasını bulmam ve değiştirmem gerekir.

Bu değiş tokuşun var olduğuna katılıyor musunuz? Öyleyse, testlerinizin okunabilir mi yoksa sürdürülebilir mi olmasını tercih edersiniz?

Yanıtlar:


68

Yinelenen kod, tıpkı diğer kodlarda olduğu gibi birim test kodunda da bir kokudur. Testlerde yinelenen kodunuz varsa, güncellemek için orantısız sayıda testiniz olduğundan uygulama kodunu yeniden düzenlemeyi zorlaştırır. Testler, test edilen kod üzerinde çalışmanızı engelleyen büyük bir yük olmaktan ziyade, güvenle yeniden düzenleme yapmanıza yardımcı olmalıdır.

Çoğaltma fikstür kurulumundaysa, setUpyöntemi daha fazla kullanmayı veya daha fazla (veya daha esnek) Oluşturma Yöntemi sağlamayı düşünün .

Çoğaltma, SUT'u işleyen koddaysa, o zaman kendinize neden birden fazla "birim" testinin tam olarak aynı işlevi kullandığını sorun.

Çoğaltma iddialarda ise, belki bazı Özel Onaylara ihtiyacınız vardır . Örneğin, birden çok test aşağıdaki gibi bir dizi iddiaya sahipse:

assertEqual('Joe', person.getFirstName())
assertEqual('Bloggs', person.getLastName())
assertEqual(23, person.getAge())

O halde assertPersonEqualyazabilmek için belki de tek bir yönteme ihtiyacınız var assertPersonEqual(Person('Joe', 'Bloggs', 23), person). (Ya da belki de eşitlik operatörünü aşırı yüklemeniz gerekiyor Person.)

Bahsettiğiniz gibi, test kodunun okunabilir olması önemlidir. Özellikle, bir testin amacının açık olması önemlidir . Pek çok test çoğunlukla aynı görünüyorsa (örneğin, çizgilerin dörtte üçü aynı veya hemen hemen aynı) önemli farklılıkları dikkatlice okuyup karşılaştırmadan fark etmenin ve fark etmenin zor olduğunu görüyorum. Dolayısıyla , yinelemeyi kaldırmak için yeniden düzenlemenin okunabilirliğe yardımcı olduğunu buldum , çünkü her test yönteminin her satırı doğrudan testin amacı ile ilgilidir. Bu, okuyucu için, doğrudan alakalı satırların rastgele bir kombinasyonundan ve sadece standart olan satırlardan çok daha faydalıdır.

Bununla birlikte, bazen testler benzer, ancak yine de önemli ölçüde farklı olan karmaşık durumları dener ve tekrarlamayı azaltmanın iyi bir yolunu bulmak zordur. Sağduyu kullanın: Testlerin okunabilir olduğunu ve amaçlarını netleştirdiğini hissediyorsanız ve testler tarafından çağrılan kodu yeniden düzenlerken teorik olarak minimum sayıda testten daha fazlasını güncelleme ihtiyacı duyuyorsanız, o zaman kusurları kabul edin ve ilerleyin daha üretken bir şeye. Daha sonra ilham geldiğinde her zaman geri dönebilir ve testleri yeniden düzenleyebilirsiniz!


30
"Yinelenen kod, tıpkı diğer kodda olduğu gibi birim test kodundaki bir kokudur." Hayır. "Testlerde yinelenen kodunuz varsa, güncellemek için orantısız sayıda testiniz olduğundan uygulama kodunu yeniden düzenlemeyi zorlaştırır." Bunun nedeni, genel API yerine özel API'yi test etmenizdir.

15
Ancak birim testlerinde yinelenen kodu önlemek için genellikle yeni mantık eklemeniz gerekir. Birim testlerinin mantık içermesi gerektiğini düşünmüyorum çünkü o zaman birim testlerinin birim testlerine ihtiyacınız olacaktır.
Petr Peller

@ user11617 lütfen "özel API" ve "genel Api" yi tanımlayın. Anladığım kadarıyla, herkese açık Api, dış dünya / 3. taraf tüketiciler tarafından görülebilen ve SemVer veya benzeri aracılığıyla açıkça sürümlendirilen API'dir, başka herhangi bir şey özeldir. Bu tanımla hemen hemen tüm Unit testleri "özel API" yi test ediyor ve bu nedenle kod kopyalamasına daha duyarlı, ki bence bu doğru.
KolA

@KolA "Genel", 3. taraf tüketiciler anlamına gelmez - bu bir web API'si değildir. Bir sınıfın genel API'si, istemci kodu tarafından kullanılması amaçlanan yöntemlere atıfta bulunur (ki bu genellikle bu kadar çok değişmez / değişmemelidir) - genellikle "genel" yöntemler. Özel API, dahili olarak kullanılan mantık ve yöntemleri ifade eder. Bunlara sınıf dışından erişilmemelidir. Erişim değiştiricileri veya kullanılan dildeki kuralı kullanarak bir sınıfta mantığı doğru şekilde kapsüllemenin önemli olmasının bir nedeni budur.
Nathan

@Nathan herhangi bir kütüphane / dll / nuget paketinin 3. taraf tüketicileri vardır, bunun bir web api olması gerekmez. Bahsettiğim şey, sadece birim testlerinin onlara doğrudan ulaşmasına izin vermek için doğrudan kütüphane tüketicileri tarafından kullanılmaması (veya en iyi ihtimalle InternalsVisibleToAttribute ile derlemeye ek açıklama yapılması) beklenen genel sınıfları ve üyeleri bildirmenin çok yaygın olduğudur. Uygulama ile birlikte bir yığın teste yol açar ve onları avantajdan çok bir yük haline getirir
KolA

186

Okunabilirlik, testler için daha önemlidir. Bir test başarısız olursa, sorunun açık olmasını istersiniz. Geliştiricinin, tam olarak neyin başarısız olduğunu belirlemek için çok fazla faktörlü test kodundan geçmesi gerekmemelidir. Test kodunuzun o kadar karmaşık hale gelmesini istemezsiniz ki, birim test testleri yazmanız gerekir.

Bununla birlikte, hiçbir şeyi engellemediği sürece, yinelemenin ortadan kaldırılması genellikle iyi bir şeydir ve testlerinizdeki yinelemeyi ortadan kaldırmak daha iyi bir API sağlayabilir. Azalan getiri noktasını geçmediğinizden emin olun.


xUnit ve diğerleri, assert çağrılarında bir 'mesaj' argümanı içerir. Geliştiricilerin başarısız test sonuçlarını hızlı bir şekilde bulmasını sağlamak için anlamlı ifadeler koymak iyi bir fikir.
02:12

1
@seand İddianızın neyi kontrol ettiğini açıklamayı deneyebilirsiniz, ancak başarısız olduğunda ve bir şekilde belirsiz bir kod içerdiğinde, geliştiricinin yine de gidip onu çözmesi gerekecektir. IMO Orada kendini tanımlayan bir koda sahip olmak daha önemlidir.
IgorK

1
@Kristopher,? Bu neden topluluk wikisi olarak gönderildi?
Pacerier

@Pacerier Bilmiyorum. Otomatik olarak topluluk wiki haline gelen şeylerle ilgili karmaşık kurallar vardı.
Kristopher Johnson

Raporların okunabilirliği testlerden daha önemlidir, özellikle entegrasyon veya uçtan uca test yapılırken, senaryolar çok az gezinmekten kaçınacak kadar karmaşık olabilir, başarısızlığı bulmakta sorun yok ama yine de benim için raporlardaki başarısızlık sorunu yeterince iyi açıklayın.
Anirudh

47

Uygulama kodu ve testler farklı hayvanlardır ve faktoring kuralları bunlara farklı şekilde uygulanır.

Yinelenen kod veya yapı, uygulama kodunda her zaman bir kokudur. Uygulamada ortak metne sahip olmaya başladığınızda, soyutlamalarınızı gözden geçirmeniz gerekir.

Öte yandan, test kodunun bir tekrarlama düzeyi sağlaması gerekir. Test kodunda tekrarlama iki hedefe ulaşır:

  • Testleri ayrı tutmak. Aşırı test bağlantısı, sözleşme değiştiği için güncellenmesi gereken tek bir başarısız testi değiştirmeyi zorlaştırabilir.
  • Testleri tek başına anlamlı tutmak. Tek bir test başarısız olduğunda, tam olarak neyi test ettiğini bulmak makul ölçüde basit olmalıdır.

Her bir test yöntemi yaklaşık 20 satırdan daha kısa kaldığı sürece test kodundaki önemsiz kopyaları göz ardı etme eğilimindeyim. Kurulum-çalıştır-doğrula ritminin test yöntemlerinde açıkça görülmesini seviyorum.

Kopyalama, testlerin "doğrula" bölümünde ortaya çıktığında, özel onaylama yöntemlerini tanımlamak genellikle yararlıdır. Elbette, bu yöntemler, yöntem adında açıkça görülebilecek, açıkça tanımlanmış bir ilişkiyi test etmelidir: assertPegFitsInHole-> iyi, assertPegIsGood-> kötü.

Test yöntemleri uzadığında ve tekrarladığında, bazen birkaç parametre alan boşlukları doldur test şablonlarını tanımlamayı yararlı buluyorum. Daha sonra gerçek test yöntemleri, uygun parametrelerle şablon yöntemine yapılan bir çağrıya indirgenir.

Programlama ve testte pek çok şeye gelince, kesin bir cevap yoktur. Bir zevk geliştirmeniz gerekir ve bunu yapmanın en iyi yolu hata yapmaktır.


8

Katılıyorum. Takas vardır, ancak farklı yerlerde farklıdır.

Durumu ayarlamak için yinelenen kodu yeniden düzenleme olasılığım daha yüksektir. Ancak, testin kodu gerçekten uygulayan kısmını yeniden düzenleme olasılığı daha düşüktür. Bununla birlikte, kodu uygulamak her zaman birkaç satır kod alırsa, bunun bir koku olduğunu düşünebilir ve test edilen gerçek kodu yeniden düzenleyebilirim. Ve bu, hem kodun hem de testlerin okunabilirliğini ve sürdürülebilirliğini artıracaktır.


Bence bu iyi bir fikir. Çok sayıda tekrarınız varsa, altında birçok testin çalıştırılabileceği ortak bir "test fikstürü" oluşturmak için yeniden düzenleme yapıp yapamayacağınıza bakın. Bu, yinelenen kurulum / sökme kodunu ortadan kaldıracaktır.
Outlaw Programmer

8

Test yardımcı yöntemlerinin birkaç farklı çeşidini kullanarak tekrarı azaltabilirsiniz .

Test kodunda tekrarlamaya üretim kodundan daha toleranslıyım, ancak bazen bu beni hayal kırıklığına uğratıyor. Bir sınıfın tasarımını değiştirdiğinizde ve geri dönüp hepsi aynı kurulum adımlarını gerçekleştiren 10 farklı test yönteminde ince ayar yapmanız gerektiğinde sinir bozucu olur.


6

Jay Fields "DSL'ler DRY değil DAMP olmalıdır" ifadesini icat etti, burada DAMP açıklayıcı ve anlamlı ifadeler anlamına geliyor . Aynısının testler için de geçerli olduğunu düşünüyorum. Açıkçası, çok fazla çoğaltma kötüdür. Ancak her ne pahasına olursa olsun tekrarların kaldırılması daha da kötüdür. Testler, amacı ortaya koyan spesifikasyonlar olarak hareket etmelidir. Örneğin, aynı özelliği birkaç farklı açıdan belirtirseniz, belirli bir miktarda çoğaltma beklenecektir.


3

Bu yüzden rspec'i SEVİYORUM:

Yardımcı olacak 2 şey var -

  • ortak davranışı test etmek için paylaşılan örnek gruplar.
    bir dizi test tanımlayabilir, ardından bu seti gerçek testlerinize 'dahil edebilirsiniz'.

  • iç içe bağlamlar.
    Temelde, yalnızca sınıftaki her biri için değil, testlerinizin belirli bir alt kümesi için bir 'kurulum' ve 'sökme' yöntemine sahip olabilirsiniz.

.NET / Java / diğer test çerçeveleri bu yöntemleri ne kadar erken benimserse, o kadar iyidir (veya testlerinizi yazmak için IronRuby veya JRuby'yi kullanabilirsiniz, ki şahsen bunun daha iyi bir seçenek olduğunu düşünüyorum)


3

Test kodunun normalde üretim koduna uygulanacak benzer bir mühendislik seviyesi gerektirdiğini hissediyorum. Okunabilirlik lehine tartışmalar kesinlikle olabilir ve bunun önemli olduğuna katılıyorum.

Bununla birlikte, deneyimlerime göre, iyi faktörlü testleri okumanın ve anlamanın daha kolay olduğunu görüyorum. Değişen bir değişken ve sondaki iddia dışında her biri aynı görünen 5 test varsa, bu tek farklı öğenin ne olduğunu bulmak çok zor olabilir. Benzer şekilde, sadece değişen değişken ve iddia görünür olacak şekilde çarpanlara ayrılırsa, o zaman testin ne yaptığını hemen anlamak kolaydır.

Test ederken doğru soyutlama düzeyini bulmak zor olabilir ve bunun yapmaya değer olduğunu düşünüyorum.


2

Daha fazla kopyalanan ve okunabilir kod arasında bir ilişki olduğunu düşünmüyorum. Test kodunuzun diğer kodunuz kadar iyi olması gerektiğini düşünüyorum. Yinelenmeyen kod, iyi yapıldığında koddan daha okunabilirdir.


2

İdeal olarak, birim testleri yazıldıktan sonra çok fazla değişmemelidir, böylece okunabilirliğe yönelirim.

Birim testlerinin olabildiğince ayrık olması, testlerin hedefledikleri belirli işlevlere odaklanmasına da yardımcı olur.

Bununla birlikte, bir dizi testte tamamen aynı olan kurulum kodu gibi, tekrar tekrar kullandığım belirli kod parçalarını deneme ve yeniden kullanma eğilimindeyim.


2

"onları daha KURU hale getirmek için yeniden düzenledi - her testin amacı artık net değildi"

Yeniden düzenleme yapmakta zorlandın gibi görünüyor. Sadece tahmin ediyorum, ancak daha az netleşirse, bu, oldukça net ve makul derecede zarif testlere sahip olmanız için hala yapacak daha çok işiniz olduğu anlamına gelmez mi?

Bu nedenle testler UnitTest'in bir alt sınıfıdır - böylece doğru, doğrulanması kolay ve net olan iyi test takımları tasarlayabilirsiniz.

Eski zamanlarda, farklı programlama dilleri kullanan test araçlarımız vardı. Testlerle hoş, çalışması kolay tasarlamak zordu (ya da imkansızdı).

Python, Java, C # - hangi dili kullanıyor olursanız olun - tam güce sahipsiniz, bu yüzden bu dili iyi kullanın. Net ve fazla gereksiz olmayan iyi görünümlü bir test kodu elde edebilirsiniz. Değiş tokuş yok.

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.