TDD'de üretim kodunu değiştirmeden geçen bir test senaryosu yazarsam, bu ne anlama geliyor?


17

Bunlar Robert C. Martin'in TDD kuralları :

  • Başarısız bir birim test geçişi yapmadığı sürece üretim kodu yazmanıza izin verilmez.
  • Başarısız olmak için yeterli olandan daha fazla birim testi yazmanıza izin verilmez; ve derleme hataları hatalardır.
  • Arızalı bir birim testini geçmek için yeterli olandan daha fazla üretim kodu yazmanıza izin verilmez.

Değerli görünen ancak üretim kodunu değiştirmeden geçen bir test yazdığımda:

  1. Bu yanlış bir şey yaptığım anlamına mı geliyor?
  2. Gelecekte bu tür testlerin yardımcı olması durumunda yazmaktan kaçınmalı mıyım?
  3. O testi orada bırakmalı mıyım yoksa kaldırmalı mıyım?

Not: Ben edildi çalışırken burada bu soruyu sormak: Bir geçen birim testi ile başlayabilir miyim? Ancak bu soruyu şimdiye kadar yeterince iyi ifade edemedim.


Alıntı yaptığınız makalede bağlantılı olan "Bowling Oyunu Kata", son adımı olarak hemen geçen bir teste sahiptir.
jscs

Yanıtlar:


21

Başarısız bir birim testi geçmeden üretim kodunu yazamayacağınızı, başından geçen bir testi yazamayacağınızı söylüyor. Kuralın amacı "Üretim kodunu düzenlemeniz gerekiyorsa, önce bir test yazdığınızdan veya değiştirdiğinizden emin olun."

Bazen bir teoriyi kanıtlamak için testler yazıyoruz. Test geçer ve bu teorimizi çürütür. Daha sonra testi kaldırmayız. Ancak, (kaynak kontrolünün desteğini aldığımızı bilerek), üretim kodunu beklemediğimiz zaman neden geçtiğini anlamak için üretim kodunu kırabiliriz.

Geçerli ve doğru bir test olduğu ortaya çıkıyorsa ve mevcut bir testi kopyalamıyorsa, orada bırakın.


Mevcut kodun test kapsamını iyileştirmek, (umarız) başarılı bir test yazmak için mükemmel bir geçerli nedendir.
Jack

13

Bunun anlamı:

  1. Önce testi yazmadan istediğiniz özelliği yerine getiren üretim kodunu yazdınız ("dini TDD" nin ihlali) veya
  2. İhtiyacınız olan özellik zaten üretim kodu tarafından yerine getiriliyor ve sadece bu özelliği kapsayacak başka bir birim testi yazıyorsunuz.

İkinci durum düşündüğünüzden daha yaygındır. Tamamen ferah ve önemsiz (ama yine de açıklayıcı) bir örnek olarak, aşağıdaki birim testini yazdığınızı varsayalım (sözde kod, çünkü tembelim):

public void TestAddMethod()
{
    Assert.IsTrue(Add(2,3) == 5);
}

Çünkü tek ihtiyacınız olan 2 ve 3'ün bir araya getirilmesinin sonucu.

Uygulama yönteminiz:

public int add(int x, int y)
{
    return x + y;
}

Ama diyelim ki şimdi birlikte 4 ve 6 eklemeliyim:

public void TestAddMethod2()
{
    Assert.IsTrue(Add(4,6) == 10);
}

Yöntemimi yeniden yazmam gerekmiyor, çünkü zaten ikinci vakayı kapsıyor.

Şimdi, Ekle işlevimin gerçekten tavana sahip bir sayı döndürmesi gerektiğini öğrendiğimizi varsayalım, diyelim ki 100. Bunu test eden yeni bir yöntem yazabilirim:

public void TestAddMethod3()
{
    Assert.IsTrue(Add(100,100) == 100);
}

Ve bu test şimdi başarısız olacak. Şimdi işlevimi yeniden yazmalıyım

public int add(int x, int y)
{
    var a = x + y;
    return a > 100 ? 100 : a;
}

geçmek için.

Sağduyu, eğer

public void TestAddMethod2()
{
    Assert.IsTrue(Add(4,6) == 10);
}

geçerse, yönteminizin kasıtlı olarak başarısız olmasını sağlamazsınız, böylece başarısız bir teste sahip olabilirsiniz, böylece o test geçişini yapmak için yeni kod yazabilirsiniz.


5
Martin örneklerini tam olarak takip ettiyseniz (ve mutlaka yapmanız gerektiğini göstermezse), geçiş yapmak için add(2,3)kelimenin tam anlamıyla 5'i döndürürdünüz. Sabit kodlu. Daha sonra , aynı anda add(4,6)kırılmadan geçerken üretim kodunu yazmaya zorlayacak testi yazacaksınız add(2,3). Sen olur sona ile return x + yancak onunla başlamak olmaz. Teoride. Doğal olarak, Martin (veya belki de başka biriydi, hatırlamıyorum) eğitim için bu tür örnekler vermeyi sever, ancak aslında bu kadar önemsiz bir kod yazmanızı beklemez.
Anthony Pegram 21:13

1
@tieTYT, genellikle, Martin'in kitaplarından doğru hatırlarsam, ikinci test örneği genellikle basit bir yöntem için genel çözümü yazmanızı sağlamak için yeterli olacaktır (ve aslında, gerçekten de İlk kez). Üçüncüye gerek yok.
Anthony Pegram

2
@tieTYT, o zamana kadar test yazmaya devam edersiniz. :)
Anthony Pegram

4
Üçüncü bir olasılık var ve bu, örneğinize aykırı: yinelenen bir test yazdınız. TDD'yi "dindar" olarak takip ederseniz, geçen yeni bir test her zaman kırmızı bir bayraktır. KURU'nun ardından , aslında aynı şeyi test eden iki test yazmamalısınız.
congusbongus

1
"Martin örneklerini tam olarak takip ettiyseniz (ve kesinlikle yapmanız gerektiğini önermezse), ekleme (2,3) geçişi yapmak için tam anlamıyla 5'i döndürürsünüz. Sabit kodlu." - Bu, her zaman benimle birlikte rendelenmiş katı bir TDD, gelecekteki bir testin gelip kanıtlanması beklentisiyle yanlış olduğunu bildiğiniz kodu yazmanız fikri . Gelecekteki test hiçbir şekilde yazılmazsa ve meslektaşları "tüm testler-yeşil" nin "tüm kod-doğru" anlamına geldiğini varsayarsa?
Julia Hayward

2

Test pasonuz ama yanılıyorsunuz. Sanırım, çünkü üretim kodu başından beri TDD değil.

Diyelim ki kanonik (?) TDD. Üretim kodu yok ama birkaç test durumu var (elbette her zaman başarısız oluyor). Geçmek için üretim kodu ekliyoruz. Ardından, daha fazla başarısız test durumu eklemek için burada durun. Yine geçmek için üretim kodunu ekleyin.

Başka bir deyişle, testiniz basit bir TDD birim testi değil bir tür işlevsellik testi olabilir. Bunlar ürün kalitesi için her zaman değerli varlıklardır.

Şahsen böyle totaliter, insanlık dışı kuralları sevmiyorum; (


2

Aslında aynı sorun dün gece bir dojo'da ortaya çıktı.

Bunun üzerine hızlı bir araştırma yaptım. Ben geldi budur:

Temelde TDD kuralları tarafından açıkça yasaklanmamıştır. Belki bir işlevin genelleştirilmiş bir girdi için doğru çalıştığını kanıtlamak için bazı ek testler gerekebilir. Bu durumda TDD uygulaması kısa bir süre için bir kenara bırakılır. TDD uygulamasından kısa bir süre ayrılmanın, bu arada üretim kodu eklenmediği sürece TDD kurallarını ihlal etmesi gerekmediğini unutmayın.

Fazlalık olmadıkları sürece ek testler yazılabilir. Eşitlik sınıfı bölümleme testi yapmak iyi bir uygulamadır. Bu, her bir denklik sınıfı için kenar kasaların ve en az bir iç çantanın test edildiği anlamına gelir.

Bununla birlikte, bu yaklaşımla ortaya çıkabilecek bir sorun, eğer testler en başından geçerse yanlış pozitif olmadığından emin olamamaktadır. Bu, testlerin doğru uygulanmadığı ve üretim kodunun doğru çalıştığı için olmadığı için geçen testlerin olabileceği anlamına gelir. Bunu önlemek için testi kırmak için üretim kodu biraz değiştirilmelidir. Bu, testin başarısız olmasını sağlarsa, test büyük olasılıkla doğru şekilde uygulanır ve testin tekrar geçmesi için üretim kodu tekrar değiştirilebilir.

Sadece katı bir TDD uygulamak istiyorsanız, en başından geçen herhangi bir ek test yazamazsınız. Öte yandan, bir işletme geliştirme ortamında, ek testler yararlı görünüyorsa, aslında TDD uygulamasından ayrılmalıdır.


0

Üretim kodunu değiştirmeden geçen bir test doğal olarak kötü değildir ve genellikle ek bir gereksinimi veya sınır durumunu tanımlamak için gereklidir. Testiniz "değerli göründüğü sürece", sizinki söylediğiniz gibi, devam edin.

Başınızı belaya soktuğunuz yer, problem alanını gerçekten anlamak yerine geçmekte olan bir testi yazmanızdır.

İki uçta hayal edebiliriz: "her ihtimale karşı" çok sayıda test yazan bir programcı, bir hata yakalarsa; ve minimum sayıda test yazmadan önce problem alanını dikkatle analiz eden ikinci bir programcı. Her ikisinin de mutlak bir değer fonksiyonu uygulamaya çalıştığını varsayalım.

İlk programcı şöyle yazar:

assert abs(-88888) == 88888
assert abs(-12345) == 12345
assert abs(-5000) == 5000
assert abs(-32) == 32
assert abs(46) == 46
assert abs(50) == 50
assert abs(5001) == 5001
assert abs(999999) == 999999
...

İkinci programcı şöyle yazar:

assert abs(-1) == 1
assert abs(0) == 0
assert abs(1) == 1

İlk programcının uygulanması aşağıdakilerle sonuçlanabilir:

def abs(n):
    if n < 0:
        return -n
    elif n > 0:
        return n

İkinci programcının uygulanması aşağıdakilerle sonuçlanabilir:

def abs(n):
    if n < 0:
        return -n
    else:
        return n

Tüm testler geçer, ancak ilk programcı sadece birkaç gereksiz test yazmamıştır (geliştirme döngülerini gereksiz yere yavaşlatır), aynı zamanda bir sınır durumunu ( abs(0)) test edememiştir .

Kendinize üretim kodunu değiştirmeden geçen testler yazıyorsanız, kendinize testlerinizin gerçekten değer katıp katmadığını veya sorun alanını anlamak için daha fazla zaman harcamanız gerekip gerekmediğini sorun.


İkinci programcı testlerle de dikkatsizdi, çünkü iş arkadaşı yeniden tanımlandı abs(n) = n*nve geçti.
Eiko

@Eiko Kesinlikle haklısın. Çok az test yazmak sizi de kötü bir şekilde ısıtabilir. İkinci programcı en azından test etmeyerek aşırı cimri idi abs(-2). Her şeyde olduğu gibi, ılımlılık anahtardır.
16'da düşünen
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.