Dinamik bir dilde alay oluştururken yazım hataları nasıl algılanır?


10

TDD yapılırken sorun oluşur. Birkaç test geçişinden sonra, bazı sınıf / modüllerin dönüş tipleri değişir. Statik olarak yazılan bir programlama dilinde, başka bir sınıfın testlerinde önceki alaycı bir nesne kullanılmışsa ve tür değişikliğini yansıtacak şekilde değiştirilmemişse, derleme hataları oluşur.

Ancak dinamik diller için, dönüş türlerindeki değişiklik algılanamayabilir ve diğer sınıfın testleri yine de geçer. Elbette, daha sonra başarısız olması gereken entegrasyon testleri olabilir, ancak birim testleri hatalı olarak geçecektir. Bundan kaçınmanın bir yolu var mı?

Önemsiz bir örnekle güncelleme (bazı makyaj dillerinde) ...

Versiyon 1:

Calc = {
    doMultiply(x, y) {return x * y}
}
//.... more code ....

// On some faraway remote code on a different file
Rect = {
    computeArea(l, w) {return Calc.doMultipy(x*y)}
}

// test for Rect
testComputeArea() { 
    Calc = new Mock()
    Calc.expect(doMultiply, 2, 30) // where 2 is the arity
    assertEqual(30, computeArea)
}

Şimdi, sürüm 2'de:

// I change the return types. I also update the tests for Calc
Calc = {
    doMultiply(x, y) {return {result: (x * y), success:true}}
}

... Daha sonra Rect çalışma zamanında bir istisna atar, ancak test yine de başarılı olur.


1
Şimdiye kadar cevapların kaçırdığı şey, sorunun değişen testleri içeren testlerle ilgili olmadığı class X, ancak testlerinin üretimde karşılaştığından farklı bir sözleşmeye class Ybağlı olduğu Xve bu nedenle test edildiği ile ilgili olmasıdır.
Bart van Ingen Schenau

Bağımlılık Enjeksiyonu ile ilgili olarak kendim SO hakkında bu soruyu sordum . Bkz. Sebep 1: Bağımlı bir sınıf çalışma zamanında değiştirilebilir (düşünme testi) . İkimiz de aynı zihniyete sahibiz, ancak büyük açıklamalardan yoksunuz.
Scott Coates

Sorunuzu tekrar okuyorum ama yorum konusunda biraz kafam karışıyor. Bir örnek verebilir misiniz?
Scott Coates

Yanıtlar:


2

Belli bir dereceye kadar bu, dinamik dillerle iş yapmanın maliyetinin sadece bir parçası. Çok fazla esneklik elde edersiniz, aksi takdirde "kendinizi asmak için yeterli ip" olarak bilinir. Dikkatli ol.

Bana göre sorun, statik olarak yazılmış bir dilde olduğundan farklı yeniden düzenleme teknikleri kullanmanızı önerir. Statik bir dilde, hangi türlerin kırılabileceğini bulmak için "derleyiciye yaslanabilmeniz" için dönüş türlerini kısmen değiştirirsiniz. Yapılması güvenlidir ve yerinde dönüş türünü değiştirmekten daha güvenlidir.

Dinamik bir dilde bunu yapamazsınız, bu nedenle dönüş türünü değiştirmek yerine yerine değiştirmek çok daha güvenlidir. Muhtemelen, ihtiyaç duyan sınıflar için yeni sınıfınızı üye olarak ekleyerek değiştirebilirsiniz.


2

Kodunuz değişiyorsa ve testleriniz hala geçiyorsa, testlerinizde bir sorun vardır (yani bir iddiayı kaçırıyorsunuz) veya kod aslında değişmedi.

Bununla ne demek istiyorum? Testleriniz, kodunuzun bölümleri arasındaki sözleşmeleri açıklar. Sözleşme ise, bir listeye bir dizidir söylemek dönüş değerini değiştirerek, "Dönüş değeri iterable olmalı" değil aslında sözleşmede bir değişiklik ve bu nedenle mutlaka bir test hatası tetiklemez.

, Bu tür kod kapsama analizi gibi araçlar (o test edilir kodunuzun hangi bölümlerinin size söylemeyeceğim, ama kullanabilirsiniz eksik iddialarını önlemek için olacak parçalar kesinlikle ne diyeceğim değildir test), cyclomatic karmaşıklığı ve NPath karmaşıklığı böyle dönüm olarak kodunuzdaki enjekte mutasyonlar ve mutasyon test ((ki size daha düşük iddiaların sayısı bağlanmış tam C1 ve C2 kod kapsama ulaşmak için gerekli vermek) trueiçin falsepozitifliği içine negatif sayılar, içine nesneleri nullvb ve kontrol testleri başarısız kılar).


+1 Testlerde veya kodda yanlış olan bir şey aslında değişmedi. Bu C ++ / Java yıl sonra alışmak biraz zaman aldı. Dinamik kod dillerindeki parçalar arasındaki sözleşme NE döndürülmemeli, ancak döndürülen şeyin ne içerdiğini ve neler yapabileceğini içermelidir.
MrFox

@suslik: Aslında bu, statik ve dinamik dillerle ilgili değil, Soyut Veri Tipleri ile Nesneye Dayalı Veri Soyutlama arasındaki Veri Soyutlama ile ilgilidir. Bu ayırt gibi davranır (tamamen farklı tip ve tamamen farklı sınıflarının örnekleri arasında olsa bile) sürece başka bir nesne benzeştirmek üzere bir nesne için yeteneğidir temel OO fikrine için. Ya da başka bir deyişle: iki nesne aynı şekilde davranırsa, sınıflarının söylediklerinden bağımsız olarak aynı türdendir. Başka bir deyişle, sınıflar tür değildir. Ne yazık ki, Java ve C # bunu yanlış anlıyor.
Jörg W Mittag

Alay edilen birimin% 100 kapsanmış olduğunu ve hiçbir iddianın eksik olmadığını varsayarsak: "foo için null döndürmeli" - "foo için boş dize döndürmelidir" gibi daha ince bir değişikliğe ne dersiniz. Birisi bu birimi ve testini değiştirirse, bazı tüketen birimler kırılabilir ve alaydan dolayı bu şeffaftır. (Ve hayır: alay konusu modülü yazarken veya kullanırken, "sözleşme" başına, boş dizeleri dönüş değeri olarak işlemek gerekmez, çünkü boş olmayan dizeleri veya yalnızca boş değer döndürmesi gerekir;)). (Etkileşimde her iki modülün de uygun entegrasyon testi bunu yakalayabilir.)
try-catch-nihayet
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.