Testlerin test ettikleri kodla aynı satırda yazılmamasının bir nedeni var mı?


91

Son zamanlarda Literatür Programlama hakkında biraz okudum ve bana şunu düşündürdü ... İyi yazılmış testler, özellikle BDD tarzı özellikler, kodun dürtüsünden çok ne yaptığını açıklamak için daha iyi bir iş yapabilir. kendi doğruluğunu doğrulama.

Test ettikleri kodla aynı satırda yazılmış testleri hiç görmedim. Bunun nedeni, dillerin aynı kaynak dosyaya yazıldığında uygulama ve test kodunu ayırmayı basitleştirme eğiliminde olmamasıdır (ve kimse bunu kolaylaştırmaz), veya insanların test kodunu uygulama kodundan ayırmasının daha temel bir nedeni var mı?


33
Doctest ile python gibi bazı programlama dilleri bunu yapmanızı sağlar.
Simon Bergot

2
BDD tarzı özelliklerin kodu açıklamaktan daha iyi olduğunu düşünebilirsiniz, ancak bu, ikisinin kombinasyonunun daha iyi olmadığı anlamına gelmez.
JeffO

5
Buradaki argümanların yarısı satır içi belgelere de uygulanır.
CodesInChaos

3
@Simon doctests, ciddi testler için çok basit, çünkü bunun için tasarlanmadılar. Dokümantasyonda otomatik olarak doğrulanabilecek kod örneklerine sahip olmak ve bunları mükemmelleştirmek için tasarlanmıştır. Şimdi, bazı insanlar bunları birim sınaması için de kullanıyorlar, ancak son zamanlarda (geçmiş yıllarda olduğu gibi) bu çok fazla zaman kaybetti, çünkü kırılgan karışıklıklara, aşırı ayrıntılı "belgelere" ve diğer karışıklıklara son verme eğilimindeydi.

7
Contract by Design, testi kolaylaştıran satır içi özelliklere izin verir.
Fuhrmanator

Yanıtlar:


89

Satır içi testler için düşünebildiğim tek avantaj, yazılacak dosya sayısını azaltmak olacaktır. Modern IDE'lerde bu gerçekten önemli bir şey değil.

Bununla birlikte, satır içi testlerde bariz dezavantajlar vardır:

  • Endişelerin ayrılmasını ihlal ediyor . Bu tartışılabilir olabilir, ancak bana göre işlevselliği test etmek onu uygulamaktan farklı bir sorumluluktur.
  • Testler / uygulama arasında ayrım yapmak için yeni dil özellikleri sunmak zorunda kalırsınız veya ikisi arasındaki çizgiyi bulanıklaştırma riskini alırsınız.
  • Daha büyük kaynak dosyalarının çalışması daha zordur: okunması zor, anlaşılması zor, kaynak denetimi çakışmaları ile uğraşmanız daha olasıdır.
  • Konuşmak için "tester" şapkanı takmanın daha zor olacağını düşünüyorum. Uygulama ayrıntılarına bakıyorsanız, belirli testleri uygulamayı atlamak için daha cazip olursunuz.

9
İlginç. Sanırım görebildiğim avantaj, "kodlayıcı" şapkanı taktığınızda testler hakkında düşünmek istediğiniz, ancak bunun tersinin doğru olmadığı iyi bir nokta.
Chris Devereux

2
Bu satırlar boyunca, bir kişinin testleri oluşturması ve birincisinin kodu uygulamasının yapılması (ve belki de istenmesi) mümkündür. Testleri sıraya koymak bunu daha da zorlaştırıyor.
Jim Nutt

6
yapabilseydim oy kullanamazdım. Bu nasıl bir cevaptır? Uygulayıcılar test yazmıyor mu? İnsanlar uygulama detaylarına bakarlarsa testleri atlıyorlar mı? "Sadece çok zor" Büyük dosyalar üzerinde anlaşmazlıklar? Ve herhangi bir şekilde bir testin bir uygulama detayıyla nasıl karıştırılabileceği ???
bharal

5
@bharal Ayrıca, "Çok zor" laf olarak mazoşizm bir aptalın erdemidir. Çözmeye çalıştığım sorun dışında her şeyin kolay olmasını istiyorum.
deworde

3
Birim testi dokümantasyon olarak kabul edilebilir. Bu, okunabilirliği artırmak için birim testlerinin yorumlarla aynı sebepten dolayı kodda bulunması gerektiğini belirtir. Bununla birlikte, bununla ilgili sorun, çok sayıda birim testi ve beklenen sonuçları belirtmeyen bir sürü test uygulamasıdır. Kod içindeki yorumlar bile, daha büyük açıklamaların yoldan çekilmesiyle - fonksiyonun dışındaki bir yorum bloğuna, ayrı bir dosyaya veya belki de bir tasarım belgesine bırakılmalıdır. Unite testleri, yorumlar gibi test edilmiş kodda tutulacak kadar kısa olursa, nadiren görülür.
Steve314

36

Bazılarını düşünebilirim:

  • Okunabilirlik. "Gerçek" kodun serpiştirilmesi ve testler gerçek kodu okumayı zorlaştıracaktır.

  • Kod şişirmek. "Gerçek" kod ve test kodunu aynı dosyalara / sınıflara / daha büyük derlenmiş dosyalara, vb. Neden olacak şekilde karıştırmak vb.

  • Müşterilerinizin / müşterilerinizin test kodunuzu görmesini istemeyebilirsiniz. ( Bu nedenden hoşlanmıyorum ... ama kapalı kaynak kodlu bir proje üzerinde çalışıyorsanız, test kodunun müşteriye yardımcı olması pek mümkün değildir.)

Şimdi bu sorunların her biri için olası geçici çözümler var. Ancak IMO, ilk etapta oraya gitmemek daha kolaydır.


Java programcılarının ilk günlerde böyle şeyler yaptığını gözlemlemeye değer; örneğin main(...)testi kolaylaştırmak için bir sınıfa bir yöntem dahil etmek. Bu fikir neredeyse tamamen ortadan kalktı. Bir tür test çerçevesi kullanarak ayrı ayrı testler yapmak endüstri uygulamasıdır.

Ayrıca, Literatür Programlamanın (Knuth tarafından tasarlandığı gibi) yazılım mühendisliği endüstrisinde asla yakalanmadığını gözlemlemeye değer.


4
+1 Okunabilirlik sorunları - test kodu, özellikle OO tasarımlarında, uygulama koduyla orantılı olarak daha büyük olabilir.
Fuhrmanator

2
Test çerçevelerini kullanarak işaret etmek için +1. Üretim koduyla aynı anda iyi bir test çerçevesi kullanmayı düşünemiyorum.
joshin4colours

1
RE: Müşterilerinizin / müşterilerinizin test kodunuzu görmesini istemeyebilirsiniz. (Bu nedenden hoşlanmıyorum ... ama kapalı kaynak kodlu bir proje üzerinde çalışıyorsanız, test kodunun müşteriye herhangi bir şekilde yardımcı olması pek mümkün değildir.) - Testleri müşteri makinesinde yapmak istenebilir. Testlerin yapılması, sorunun ne olduğunu hızlı bir şekilde tespit etmek ve müşterilerdeki farklılıkları saptamak için yardımcı olabilir ..
altmış ayak parmakları

1
@sixtyfootersdude - Bu oldukça sıradışı bir durum. Ve kapalı kaynak geliştirdiğinizi varsayarsak, testlerinizi standart ikili dağıtımınıza dahil etmek istemezsiniz. (Müşterinin çalıştırmasını istediğiniz testleri içeren ayrı bir paket oluşturacaktınız.)
Stephen C

1
1) Cevabımın ilk kısmını üç nedenden dolayı özledim mi? Orada bazı “eleştirel düşünce” vardı… 2) Java programcılarının bunu yaptığını söylediğim ikinci kısmı kaçırdınız mı, ama şimdi yapmıyorlar mı? Ve programcıların bunu yapmaktan vazgeçtiği apaçık ... iyi bir nedenle mi?
Stephen C,

14

Aslında, Design By Contract'ı bunu yaptığınızı düşünebilirsiniz . Sorun çoğu programlama dilinin bu şekilde kod yazmanıza izin vermemesidir :( Önkoşulları elle test etmek çok kolaydır, ancak posta koşulları, kod yazma şeklinizi değiştirmeden gerçek bir sorundur (büyük bir negatif IMO).

Michael Feathers'ın bununla ilgili bir sunumu var ve bu, kod kalitesini geliştirebileceğinizden bahsettiğiniz yollardan biri.


13

Kodunuzdaki sınıflar arasında sıkı bağlantıdan kaçınmaya çalıştığınız birçok nedenden dolayı, testler ve kod arasında gereksiz bağlantıdan kaçınmak iyi bir fikirdir.

Oluşturma: Testler ve kod farklı zamanlarda farklı kişiler tarafından yazılabilir.

Kontrol: Gereksinimleri belirtmek için testler kullanılıyorsa, kesinlikle onları kimin değiştirebileceği ve gerçek kodun ne olduğu konusunda farklı kurallara tabi olmalarını istersiniz.

Yeniden kullanılabilirlik: Testleri satır içi yaparsanız, başka bir kod parçasıyla kullanamazsınız.

İşi doğru yapan bir kod parçasına sahip olduğunuzu, ancak performans, bakım, her neyse arzulanan çok şey bıraktığınızı hayal edin. Bu kodu yeni ve geliştirilmiş kodla değiştirmeye karar veriyorsunuz. Aynı test kümesini kullanmak, yeni kodun eski kodla aynı sonuçları verdiğini doğrulamanıza yardımcı olabilir.

Seçilebilirlik: Testleri koddan ayrı tutmak, hangi testleri yapmak istediğinizi seçmenizi kolaylaştırır.

Örneğin, yalnızca üzerinde çalışmakta olduğunuz kodla ilgili küçük bir test paketi ve tüm projeyi test eden daha büyük bir paketiniz olabilir.


Sebepleriniz konusunda şaşkınım: TDD zaten test oluşturmanın üretim kodu olarak (veya aynı zamanda) üretim kodu olarak yapıldığını ve aynı kodlayıcı tarafından yapılması gerektiğini söylüyor! Ayrıca, testlerin neredeyse şartlara benzer olduğunu da ima ediyorlar. Elbette, bu itirazlar TDD dogmaya abone değilseniz (bu kabul edilebilir olurdu, ancak bunu açıkça belirtmelisiniz!) Uygulanmaz. Ayrıca, "yeniden kullanılabilir" bir test tam olarak nedir? Testler tanım olarak test ettikleri koda özgü değil midir?
Andres F.

1
@AndresF. Hayır, testler test ettikleri koda özgü değildir; Test ettikleri davranışa özgüdürler. Öyleyse, Widget'ın doğru şekilde davrandığını doğrulayan bir dizi testle tamamlanmış bir Widget modülünüz olduğunu varsayalım. İş arkadaşınız, Widget ile aynı şeyi yapmayı ancak üç kat daha hızlı yapmayı iddia eden BetterWidget ile geldi. Widget için yapılan testler, Widget'ın kaynak koduna, Literatür Programlama'nın kaynak koduna dokümanları gömdüğü şekilde yerleştirildiyse, bu testlerin aynı Widget'ın yaptığını doğrulamak için BetterWidget'a uygulayamazsınız.
Caleb

@AndresF. TDD'yi takip etmediğinizi belirtmenize gerek yok. kozmik bir varsayılan değil. Yeniden kullanım noktası gelince. Bir sistemi test ederken iç kısımlara değil giriş ve çıkışlara önem veriyorsunuz. Öyleyse, tıpkı onun gibi davranan ancak farklı şekilde uygulanan yeni bir sistem oluşturmanız gerektiğinde, hem eski hem de yeni sistemde çalıştırabileceğiniz testlere sahip olmak harikadır. bu bana bir kereden fazla oldu, bazen hala eskimiş durumda iken yeni sistem üzerinde çalışmanız ya da yan yana koşmanız gerekir. Facebook’un nasıl test edildiğine bir göz atın, tepkimeye girecek tepki testleriyle fiber reaksiyon lifini ’görün.
user1852503,

10

İşte aklıma gelen bazı ek nedenler:

  • ayrı bir kütüphanede testlere sahip olmak, sadece bu kütüphaneyi test çerçevenize bağlamayı ve üretim kodunuza bağlamayı kolaylaştırır (bazı önişlemcilerden kaçınılabilir, ancak neden daha kolay bir çözüm testleri yazmaksa ayrı bir yer)

  • Bir fonksiyonun, bir sınıfın, bir kütüphanenin testleri genellikle "kullanıcılar" bakış açısıyla yazılır (bu fonksiyon / sınıf / kütüphanenin kullanıcısı). Böyle bir "kod kullanma" tipik olarak ayrı bir dosyaya veya kütüphaneye yazılır ve bu durumu taklit ederse bir test daha net veya "daha gerçekçi" olabilir.


5

Testler satır içi olsaydı, ürünü müşterinize gönderirken test etmek için gereken kodu kaldırmak gerekir. Dolayısıyla bunu testleri saklamak fazladan yer basitçe kodu arasında ayıran Eğer ihtiyaç ve kod müşteri ihtiyacı var.


9
İmkansız değil. LP'de olduğu gibi ek bir ön işleme aşaması gerektirir. Örneğin, kolayca C dilinde veya bir derleme dili dili ile yapılabilir.
Chris Devereux

Bana işaret ettiğin için +1. Bunu temsil etmek için cevabımı değiştirdim.
mhr

Her durumda kod boyutunun önemli olduğu varsayımı da vardır. Sırf bazı durumlarda önemli olduğu için, her durumda önemli olduğu anlamına gelmez. Programcıların kaynak kod boyutunu optimize etmek için yönlendirilmediği pek çok ortam vardır. Öyle olsaydı, çok fazla sınıf yaratmazlardı.
zumalifeguard

5

Bu fikir, sadece nesne tabanlı veya nesne yönelimli bir tasarım bağlamında bir "Self_Test" yöntemine karşılık gelir. Ada gibi derlenmiş bir nesne tabanlı dil kullanılıyorsa, tüm otomatik test kodu derleyici tarafından üretim derlemesi sırasında kullanılmamış (hiç çağrılmadı) olarak işaretlenir ve bu nedenle hepsi en iyi duruma getirilir - hiçbiri ekranda görünmez sonuçta çalıştırılabilir.

Bir "Self_Test" yöntemi kullanmak son derece iyi bir fikirdir ve programcılar kaliteyle gerçekten ilgileniyorlarsa, hepsi bunu yapardı. Yine de önemli konulardan biri, "Self_Test" yönteminin, uygulama detaylarının hiçbirine erişememesi ve bunun yerine sadece nesnenin spesifikasyonunda yayınlanan tüm diğer metotlara dayanması gerektiği için yoğun bir disipline sahip olması gerektiğidir. Açıkçası, öz sınama başarısız olursa, uygulamanın değişmesi gerekecektir. Öz sınama, nesnenin yöntemlerinin tüm yayınlanmış özelliklerini titizlikle sınamalıdır, ancak hiçbir zaman belirli bir uygulamanın ayrıntılarına hiçbir zaman güvenmez.

Nesneye dayalı ve nesneye yönelik diller, test edilen nesnenin dışındaki yöntemlerle ilgili olarak tam olarak bu tür bir disiplin sağlarlar (nesnenin özelliklerini zorlarlar, uygulama ayrıntılarına erişimi engeller ve bu tür bir girişim tespit edilirse bir derleme hatası oluştururlar) ). Ancak, nesnenin kendi iç yöntemlerine tüm uygulama detaylarına tam erişim sağlanır. Bu yüzden öz sınama yöntemi benzersiz bir durumda: doğası nedeniyle bir iç yöntem olması gerekiyor (öz sınama açıkça test edilen nesnenin bir yöntemidir), ancak bir dış yöntemin tüm derleyici disiplinini alması gerekiyor ( nesnenin uygulama detaylarından bağımsız olmalıdır). Herhangi bir programlama dili, bir nesneyi disipline etme yeteneği sağlıyorsa s dış bir yöntemmiş gibi iç yöntemi. Yani bu önemli bir programlama dili tasarım konusudur.

Doğru programlama dili desteği yokken, bunu yapmanın en iyi yolu bir eşlik eden nesne oluşturmaktır. Diğer bir deyişle, kodladığınız her nesne için ("Big_Object" olarak adlandıralım), ayrıca "real" nesnesinin adıyla birleştirilen standart bir sonekten oluşan ikinci bir eşlik eden nesne oluşturursunuz (bu durumda, "Big_Object_Self_Test ") ve belirtimi tek bir yöntemden oluşuyor (" Big_Object_Self_Test.Self_Test (This_Big_Object: Big_Object) return Boolean; "). Eşlik eden nesne daha sonra ana nesnenin özelliklerine bağlı olacaktır ve derleyici, eşlik eden nesnenin uygulanmasına karşı bu tarifnamenin tüm disiplinini tamamen uygulayacaktır.


4

Bu, satır içi testlerin yapılmadığını öne süren çok sayıda yoruma yanıt olarak geliyor; çünkü test kodunu sürüm oluşturmalarından kaldırmak imkansız. Bu doğru değil. Hemen hemen tüm derleyiciler ve derleyiciler bunu zaten desteklemektedir; C, C ++, C # gibi derlenmiş dillerle bu derleyici yönergeleri adı verilen şeyle yapılır.

C # durumunda (c ++ 'ın da kullandığına inanıyorum, sözdizimi hangi derleyiciyi kullandığınıza bağlı olarak biraz farklı olabilir) bu nasıl yapabilirsiniz.

#define DEBUG //  = true if c++ code
#define TEST /* can also be defined in the make file for c++ or project file for c# and applies to all associated .cs/.cpp files */

//somewhere in your code
#if DEBUG
// debug only code
#elif TEST
// test only code
#endif

Bu, derleyici yönergelerini kullandığından, bayraklar ayarlanmadığında oluşturulan yürütülebilir dosyalarda kod bulunmaz. Bu aynı zamanda çoklu platformlar / donanımlar için "bir kez yaz, iki kez derle" programlarını böyle yapar.


2

Perl kodumuzla satır içi testleri kullanıyoruz. Bir satırda Test :: Inline , satır içi kodundan test dosyaları üreten bir modül var .

Testlerimi organize etme konusunda özellikle iyi değilim ve inline edildiklerinde daha kolay ve daha kolay kullanılmalarını sağladım.

Birkaç endişeye cevap vermek:

  • Satır içi testler POD bölümlerinde yazılmıştır, bu nedenle gerçek kodun bir parçası değildirler. Tercüman tarafından yok sayılırlar, bu yüzden kod ihlali yoktur.
  • Test bölümlerini gizlemek için Vim katlama kullanıyoruz . Gördüğünüz tek şey, test edilen her yöntemin üzerinde tek bir satırdır +-- 33 lines: #test----. Testle çalışmak istediğinizde, sadece genişletin.
  • Test :: Inline modülü testleri normal TAP uyumlu dosyalara "derler", böylece geleneksel testlerle birlikte bulunabilirler.

Referans için:


1

Erlang 2 aslında satır içi testleri destekliyor. Kodda kullanılmayan (örneğin bir değişkene atanmış veya geçen) herhangi bir boole ifadesi otomatik olarak bir test olarak değerlendirilir ve derleyici tarafından değerlendirilir; Eğer ifade yanlışsa, kod derlenmez.


1

Testleri ayırmanın başka bir nedeni, gerçek uygulamadan ziyade test için sık sık ek veya hatta farklı kütüphaneler kullanmanızdır. Testleri ve uygulamayı karıştırırsanız, uygulamadaki test kitaplıklarının yanlışlıkla kullanılması derleyici tarafından yakalanamaz.

Ayrıca, testler test ettikleri uygulama bölümlerinden çok daha fazla kod satırına sahip olma eğilimindedir, bu nedenle tüm testler arasında uygulamayı bulmakta sorun yaşarsınız. :-)


0

Bu doğru değil. Ünite testlerinizi, özellikle üretim rutini saf olduğunda, üretim kodu olduğunda, üretim kodunun yanına yerleştirmek çok daha iyidir.

Örneğin, .NET'te geliştiriyorsanız, test kodunuzu üretim meclisine koyabilir ve göndermeden önce bunları silmek için Neşter kullanabilirsiniz .

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.