Sınama amacıyla kesinlikle kodu değiştirmek kötü bir uygulama mıdır?


77

Bir programcı meslektaşımla birlikte çalışan bir kod parçasını sadece test edilebilir hale getirmek için değiştirmenin iyi mi yoksa kötü bir uygulama mı olduğu konusunda tartışmalıyım (örneğin, birim testleri aracılığıyla).

Benim fikrim elbette, iyi nesneye yönelik ve tabii ki yazılım mühendisliği uygulamalarını sürdürme sınırları dahilinde ("her şeyi halka açık yapma" değil).

Meslektaşımın görüşü, yalnızca test amaçlı olarak kodun (çalışan) değiştirilmesinin yanlış olduğu yönünde.

Sadece basit bir örnek, bazı bileşenler tarafından kullanılan bu kod parçasını düşünün (C # ile yazılmış):

public void DoSomethingOnAllTypes()
{
    var types = Assembly.GetExecutingAssembly().GetTypes();

    foreach (var currentType in types)
    {
        // do something with this type (e.g: read it's attributes, process, etc).
    }
}

Bu kodun asıl işi yapacak başka bir yöntemi çağırmak için değiştirilebileceğini önerdim:

public void DoSomething(Assembly asm)
{
    // not relying on Assembly.GetExecutingAssembly() anymore...
}

Bu yöntem üzerinde çalışmak için bir Assembly nesnesini alır ve testin yapılması için kendi Meclisinizi geçmenizi mümkün kılar. Meslektaşım bunun iyi bir uygulama olduğunu düşünmedi.

İyi ve yaygın bir uygulama olarak neler kabul edilir?


5
Değiştirilen yönteminiz bir değil Type, bir parametre olarak almalıdır Assembly.
Robert Harvey

Haklısın - Tür veya Montaj, önemli olan, kodun bunu bir parametre olarak vermesine izin vermesi gerektiğidir, ancak bu işlevsellik sadece test için kullanılmak üzere
görünse de

5
Otomobilinizde "test" için bir ODBI portu var - işler mükemmelse ihtiyaç duyulmazdı. Tahminimce araba sen onun yazılımından daha güvenilir.
mattnz

24
“Çalıştığı” kodunun nasıl bir güvencesi var?
Craige

3
Tabii ki - yapın. Test edilmiş kod zamanla kararlıdır. Ancak, test edilebilirlik için bir düzeltmeden ziyade bazı özellik iyileştirmeleriyle birlikte gelirlerse, yeni ortaya çıkan hataları açıklamak için çok daha kolay bir zamana sahip olacaksınız
Petter Nordlander

Yanıtlar:


135

Daha fazla test edilebilir hale getirmek için kodu değiştirmek, test edilebilirliğin ötesinde faydalar sağlar. Genel olarak, daha test edilebilir olan kod

  • Bakımı kolaydır.
  • Sebep olması daha kolay,
  • Daha gevşek bağlanmış mı ve
  • Mimari olarak daha iyi bir genel tasarıma sahiptir.

3
Cevabımda bunlardan bahsetmedim, ama tamamen katılıyorum. Kodunuzu daha fazla test edilebilir hale getirmek için elden geçirmeniz, birkaç mutlu yan etkiye sahip olma eğilimindedir.
Jason Swett

2
+1: Genelde aynı fikirdeyim. Kuralların test edilebilir hale getirilmesinin bu diğer yararlı hedeflere zarar verdiği ve bu durumlarda test edilebilirliğin en düşük önceliğe sahip olduğu kesin durumlar vardır. Ancak genel olarak, kodunuz test etmek için yeterince esnek / genişletilebilir değilse, kullanmak veya incelikle yaşlanmak için yeterince esnek / genişletilemez.
Telastyn

6
Test edilebilir kod daha iyi koddur. Etrafında testler içermeyen kodun değiştirilmesinde her zaman doğal risk vardır ve bu riski son derece kısa vadede azaltmanın en kolay ve en ucuz yolu, onu gerçekten rahat bırakmaktır, ki bu gerçekten iyi olana kadar ... Kodu değiştirmek için Yapmanız gereken, birim testinin faydalarını meslektaşınıza satmak; Herkes birim testine dahilse, o zaman kodun test edilebilir olması gerektiği tartışılmaz. Herkes birim testine dahil değilse, hiçbir anlamı yoktur.
guysherman

3
Kesinlikle. Kendi kodumun yaklaşık 10k kaynak satırı için birim testleri yazdığımı hatırlıyorum. Kodun mükemmel çalıştığını biliyordum ama testler beni bazı durumları yeniden düşünmeye zorladı. Kendime "Bu yöntem tam olarak ne yapıyor?" Diye sormak zorunda kaldım. Çalışma kodunda birkaç hataya yalnızca yeni bir bakış açısıyla bakarak buldum.
Sulthan

2
Yukarı düğmesini tıklatmaya devam ediyorum, ancak size yalnızca bir puan verebilirim. Şu andaki işverenim aslında birim sınamalarını uygulamamıza izin vermeyecek kadar kısa görüşlü ve hala sınava dayalı çalışıyormuşum gibi kodumu bilinçli bir şekilde yazmaktan yararlanıyorum.
AmericanUmlaut

59

Oyunda (görünüşte) muhalif güçler var .

  • Bir yandan, kapsülleme zorlamak istiyorsun
  • Öte yandan, yazılımı test edebilmek istediğinizde

Tüm 'uygulama detaylarını' gizli tutma savunucuları genellikle enkapsülasyonu sürdürme arzusuyla motive olurlar. Ancak, her şeyi kilitli ve kullanılamaz durumda tutmak , kapsülleme konusunda yanlış anlaşılmış bir yaklaşımdır. Her şeyi kullanılamaz kılmak en büyük hedefse, kapsanan tek gerçek kod şudur:

static void Main(string[] args)

Meslektaşınız bunu kodunuzdaki tek erişim noktası yapmayı mı teklif ediyor? Diğer tüm kodların harici arayanlar tarafından erişilememesi gerekir mi?

Zorlukla. Öyleyse, bazı metotları halka açık hale getirmenin nesi iyi? Sonunda öznel bir tasarım kararı değil mi?

Tam değil. Programcılara bilinçsiz bir seviyede bile rehberlik etme eğilimi, yine de kapsülleme kavramıdır. Değişmeyenlerini düzgün bir şekilde koruduğunda, genel bir yöntemi ifşa etme konusunda kendini güvende hissediyorsun .

Ben onun değişmezleri korumaz özel yöntem maruz istemem, ama çoğu zaman bunu böylece değiştirebilirsiniz gelmez onun değişmezleri korumak ve daha sonra TDD ile, elbette (halka maruz, sen yap başka bir yolla).

Test edilebilirlik için bir API açmak iyi bir şeydir , çünkü gerçekte yaptığınız şey Açık / Kapalı Prensibi uygulamaktır .

API'nizin yalnızca tek bir arayanı varsa, API'nizin ne kadar esnek olduğunu bilmiyorsunuz. Muhtemelen, oldukça esnek. Testler , ikinci bir müşteri görevi görür ve API'nizin esnekliği hakkında size değerli geri bildirimler sunar .

Bu nedenle, eğer testler API'nizi açmanız gerektiğini gösteriyorsa, o zaman yapın; ancak karmaşıklığı gizleyerek değil, karmaşıklığı başarısız bir şekilde ortaya koyarak kapsüllemeyi sürdürün.


3
+1 Değişmeyenleri koruduğu zaman bir kamu yöntemini ifşa etmenin güvende olduğunu hissediyorsunuz.
shambulator

1
Cevabını çok seviyorum! :) Kaç kez duydum: "Kapsülleme, bazı metot ve özellikleri özel yapma sürecidir". Nesne yönelimli olarak programlama yaptığınız zaman, bunun nedeni nesnelerle programlama yapmanızdır. :( Bağımlılık enjeksiyonunun ustasından çok net bir cevap geldiğine şaşırmadım, eski zaafımın eski kodu hakkında beni gülümsetmek için cevabınızı kesinlikle birkaç kez okuyacağım
Samuel

Cevabınıza birkaç tweaks ekledim. Bir kenara olarak, Özellikleri Kapsülleme gönderinizi okudum ve Otomatik Özellikleri kullanmak için şimdiye kadar duyduğum tek çekici neden, bir genel değişkeni bir genel özellik olarak değiştirmenin ikili uyumluluğu bozması; Başından itibaren Otomatik Özellik olarak gösterilmesi, müşteri kodunu kırmadan doğrulama veya diğer dahili işlevlerin eklenmesini sağlar.
Robert Harvey,

21

Bağımlılık enjeksiyonundan bahsediyor gibisin . Bu gerçekten yaygındır ve IMO, test edilebilirlik için oldukça gereklidir.

Sadece test edilebilir hale getirmek için kodu değiştirmenin iyi bir fikir olup olmadığına dair daha geniş bir soruyu ele almak için, şu şekilde düşünün: kodun a) yürütülecek, b) insanlar tarafından okunacak ve c) test edilecek. Üçü de önemlidir ve eğer kodunuz her üç sorumluluğu da yerine getirmiyorsa, bunun çok iyi bir kod olmadığını söyleyebilirim. Öyleyse uzaklaş!


DI ana soru değil (sadece bir örnek vermeye çalışıyordum), asıl mesele, sadece test etmek amacıyla, orijinal olarak yaratılması amaçlanmayan başka bir yöntem sunmanın uygun olup olmadığıydı.
saat

4
Biliyorum. İkinci paragrafımdaki ana noktanıza "evet" yazdığımı sanıyordum.
Jason Swett

13

Biraz tavuk ve yumurta problemi.

Kodunuzun iyi bir test kapsamına sahip olmasının iyi olmasının en büyük sebeplerinden biri, korkusuzca yeniden yönlendirmenize izin vermesidir. Ancak, iyi bir test kapsamı elde etmek için kodu yeniden gözden geçirmeniz gereken bir durumdasınız! Ve meslektaşın korkuyor.

Meslektaşının bakış açısını görüyorum. İşe yarayan bir kodunuz var (muhtemelen), ve eğer gidip tekrar kırdıysanız - ne sebeple olursa olsun - onu parçalama riski vardır.

Ancak bu devam eden bakım ve modifikasyona sahip olması beklenen kod ise, üzerinde çalıştığınız her seferde bu riski taşıyacaksınız. Ve yeniden düzenleme şimdi ve bazı test kapsama alma şimdi sen kontrollü şartlar altında, bu riski almak ve gelecekteki değişiklik için daha iyi şekle kodu almak sağlayacaktır.

Dolayısıyla, bu belirli kod temeli oldukça statik olmadıkça ve gelecekte önemli işler yapması beklenmediği sürece, yapmak istediğiniz şeyin iyi bir teknik uygulama olduğunu söyleyebilirim.

Tabii ki, iyi bir pratiği bir bütün 'solucanlar bir kutu olabilir ..


Önemli bir endişe. Genellikle, IDE destekli refactoringleri özgürce yapıyorum çünkü oradaki herhangi bir şeyi kırma şansı çok düşük. Yeniden düzenleme daha fazla dahil olduğunda, yalnızca kodu yine de değiştirmeniz gerektiğinde yapardım. Maddeleri değiştirmek için riskleri azaltmak için testler yapmanız gerekir, böylece işletme değeri elde edersiniz.
Hans-Peter Störr

Mesele şu: Eski kodu saklamak istiyor muyuz, çünkü mevcut derleme için sorgulama nesnesine sorumluluk vermek istiyoruz ya da bazı ortak özellikler eklemek istemiyoruz ya da yöntem imzasını değiştirmek istemiyoruz? Kodun SRP'yi ihlal ettiğini düşünüyorum ve bu nedenle meslektaşları ne kadar korktuğuna bakılmaksızın yeniden düzenlenmelidir. Bu, birçok kullanıcı tarafından kullanılan bir genel API ise, bir cephe uygulaması veya eski kodlara çok fazla değişiklik yapılmasını önleyen bir arabirim vermenize yardımcı olan herhangi bir şey gibi bir strateji düşünmeniz gerekir.
Samuel,

7

Bu sadece diğer cevaplardan vurgu bir fark olabilir, ama ben kodu derim değil refactored kesinlikle edilebilirliğini artırmak için. Test edilebilirlik bakım için son derece önemlidir, ancak test edilebilirlik başlı başına bir amaç değildir . Bu nedenle, bu kodun bazı işlerin sona ermesi için bakıma ihtiyacı olacağını tahmin edene kadar bu tür yeniden düzenleme işlemlerini erteleyeceğim.

Bu kod biraz bakım gerektireceğini belirlemek noktada, bu test edilebilirliği için planı ayrı için iyi bir zaman olacaktır. İş durumunuza bağlı olarak, tüm kodların sonunda bir miktar bakım gerektireceği varsayımı geçerli olabilir , bu durumda diğer cevaplarla birlikte çizdiğim ayrım ( örneğin, Jason Swett'in cevabı ) ortadan kalkar.

Özetlemek gerekirse: test edilebilirlik tek başına (IMO) bir kod tabanını yeniden yapılandırmak için yeterli bir neden değildir. Test edilebilirliğin, bir kod tabanında bakım yapılmasına izin vermede değerli bir rolü vardır, ancak yeniden düzenlemenizi yürütmesi gereken kodunuzun işlevini değiştirmek bir iş gereksinimidir. Böyle bir iş gereksinimi yoksa, müşterilerinizin umursayacağı bir şey üzerinde çalışmak muhtemelen daha iyi olacaktır.

(Yeni kod, tabii ki aktif bir şekilde korunuyor, bu yüzden test edilebilir olmak için yazılmalıdır.)


2

Bence meslektaşın yanlış.

Diğerleri, bunun neden zaten iyi bir şey olduğunun nedenlerinden bahsetti, ancak bunu yapmanız için önünüze devam ettiği sürece, iyi olmalısınız.

Bu uyarıların nedeni, kodda herhangi bir değişiklik yapmanın, yeniden test edilmek zorunda olan kodun maliyetidir. Ne yaptığınıza bağlı olarak, bu test çalışması aslında kendi başına büyük bir çaba olabilir.

Şirketinize / müşterinize fayda sağlayacak yeni özellikler üzerinde çalışmaya karşı yeniden yapılanma kararını vermek için mutlaka yeriniz olmayabilir.


2

Kod içerisindeki tüm yolların kullanılıp kullanılmadığını kontrol etmede birim testinin bir parçası olarak kod kapsamı araçlarını kullandım. Oldukça iyi bir kodlayıcı / test cihazı olarak, genellikle kod yollarının% 80-90'ını kapsıyorum.

Açıklanamayan yolları araştırdığımda ve bazıları için çaba gösterdiğimde, “asla gerçekleşmeyecek” hata durumları gibi hataları keşfettim. Bu yüzden evet, kodu değiştirmek ve test kapsamını kontrol etmek daha iyi kodlar üretmenizi sağlar.


2

Buradaki problemin, test araçlarının berbat olması. Bu nesneyle alay edip test yönteminizi değiştirmeden çağırabiliyor olmalısınız - çünkü bu basit örnek gerçekten basit ve değiştirilmesi kolaydır, ancak çok daha karmaşık bir şey olduğunda ne olur.

Bir çok insan kodlarını, bu kod değişikliklerini gerektiren alaycı ve birim sınama araçlarını kullanarak birim sınamasını etkinleştirmek için IoC, DI ve arabirim tabanlı sınıfları tanıtmak için değiştirdi. Bunların sağlıklı bir şey olduğunu düşünmüyorum, oldukça basit ve basit bir kod gördüğünüzde, her bir sınıf yöntemini her şeyden tamamen ayırma ihtiyacına bağlı olarak tamamen karmaşık bir etkileşimler kabusuna dönüşüyor. . Yaralanmaya hakaret eklemek için, özel yöntemlerin birim test edilip edilmemesi gerektiği konusunda birçok tartışmamız var! (elbette onlar gerekir, ne '

Elbette, sorun o zamanlar test takımının yapısındadır.

Bu tasarım değişikliklerini sonsuza dek yatağa atabilecek daha iyi araçlar var. Microsoft, statik nesneler de dahil olmak üzere somut nesneleri saplamanıza izin veren Fakes (nee Moles) özelliğine sahiptir, bu nedenle kodunuzu araca uyacak şekilde değiştirmeniz gerekmez. Sizin durumunuzda, Fakes'i kullandıysanız, GetTypes çağrısını geçerli ve geçersiz test verilerini döndüren kendiniz ile değiştirirsiniz - ki bu oldukça önemli, önerilen değişikliğiniz bunun için bir şey sağlamaz.

Cevaplamak için: meslektaşınız haklı, ama muhtemelen yanlış sebeplerden dolayı. Test etmek için kod değiştirmeyin, test aracınızı değiştirin (ya da tüm bu ince taneli testler yerine bütünleştirme tarzı birim testlerine sahip olmak için tüm test stratejinizi değiştirin).

Martin Fowler'ın bu alanda bir tartışması var. Mocks Stubs değil.


1

Ünite testi ve hata ayıklama günlüklerinin kullanılması iyi ve yaygın bir uygulamadır . Birim testleri, programda daha fazla değişiklik yaparsanız, eski işlevselliğinizin bozulmamasını sağlar. Hata ayıklama günlükleri, programı çalışma zamanında izlemenize yardımcı olabilir.
Bazen, bunun ötesinde bile, sadece test amaçlı bir şeye sahip olmamız gerekir. Bunun için kodu değiştirmek sıradışı değildir. Ancak bundan dolayı üretim kodunun etkilenmemesine özen gösterilmelidir. C ++ ve C'de bu , derleme zamanı varlığı olan MACRO kullanılarak gerçekleştirilir . Ardından, test kodu üretim ortamında hiç görünmüyor. C # içinde böyle bir hüküm var mı bilmiyorum.
Ayrıca, programınıza test kodu eklediğinizde, açıkça görülebilmelidir.bu kod bölümünün bazı test amaçları için eklendiğini Veya kodu anlamaya çalışan geliştirici basitçe kodun o bölümünü terletecek.


1

Örnekleriniz arasında bazı ciddi farklılıklar var. Bu durumda , mevcut derlemedeki türler için geçerli olan DoSomethingOnAllTypes()bir sonuç vardır do something. Ancak, DoSomething(Assembly asm)açıkça, herhangi bir montajı yapabileceğinizi gösterir.

Bunu işaret etmemin nedeni, orijinal nesnenin sınırları dışında sadece test için sadece bağımlılık-enjeksiyon adımları olması. " Her şeyi halka açık yapma " dedin, biliyorum , ama bu modelin en büyük hatalarından biri, bunu yakından takip ediyor: nesnenin yöntemlerini amaçlanmadıkları kullanımlara açmak.


0

Sorunuz meslektaşınızın tartışmakta olduğu bir bağlam ifade etmedi, bu yüzden spekülasyon için yer var

“kötü uygulama” ya da değişikliklerin nasıl ve ne zaman yapıldığına bağlı değildir .

İsteğime göre, bir metodu çıkartma örneğiniz DoSomething(types)tamam.

Ancak bu gibi tamam değil kodu gördüm :

public void DoSomethingOnAllTypes()
{
  var types = (!testmode) 
      ? Assembly.GetExecutingAssembly().GetTypes() 
      : getTypesFromTestgenerator();

  foreach (var currentType in types)
  {
     if (!testmode)
     {
        // do something with this type that made the unittest fail and should be skipped.
     }
     // do something with this type (e.g: read it's attributes, process, etc).
  }
}

Bu değişiklikler, kodun anlaşılmasını zorlaştırdı çünkü olası kod yolu sayısını artırdınız.

Ne ben ile demek nasıl ve ne zaman :

Eğer çalışan bir uygulamanız varsa ve "test-yeteneklerini uygulama" uğruna, değişiklikleri yaptınız, o zaman uygulamanızı yeniden test etmeniz gerekir, çünkü DoSomething()metodunuzu bozmuş olabilirsiniz .

if (!testmode)Ekstre yönteme göre daha fazla anlaşılması difficulilt ve testtir.

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.