TDD yardımcı olmadığında koddaki mantıksal hatalardan nasıl kaçınılır?


67

Geçenlerde bir olayın kaç yaşında olduğunu insan dostu bir şekilde gösteren küçük bir kod parçası yazıyordum. Örneğin, etkinliğin “Üç hafta önce” veya “Bir ay önce” veya “Dün” olduğunu gösterebilir.

Gereksinimler nispeten açıktı ve bu teste dayalı gelişim için mükemmel bir durumdu. Testleri birer birer yazdım, her testi geçmek için gereken kodu uyguladık ve her şey mükemmel çalışıyor gibiydi. Üretimde bir hata ortaya çıkana kadar.

İşte ilgili kod parçası:

now = datetime.datetime.utcnow()
today = now.date()
if event_date.date() == today:
    return "Today"

yesterday = today - datetime.timedelta(1)
if event_date.date() == yesterday:
    return "Yesterday"

delta = (now - event_date).days

if delta < 7:
    return _number_to_text(delta) + " days ago"

if delta < 30:
    weeks = math.floor(delta / 7)
    if weeks == 1:
        return "A week ago"

    return _number_to_text(weeks) + " weeks ago"

if delta < 365:
    ... # Handle months and years in similar manner.

Testler, bugün, dün, dört gün önce, iki hafta önce, bir hafta önce vb. Meydana gelen bir olayın durumunu kontrol ediyordu ve kod buna göre oluşturuldu.

Kaçırdığım şey, bir olayın bir gün önce olduğu bir günden bir gün önce gerçekleşebileceğidir: örneğin, yirmi altı saat önce gerçekleşen bir olay bir gün önce olurken, tam olarak dün değil, şu an tam olarak 1 ise, bu tam olarak bir nokta. bir şey, ancak deltabir tamsayı olduğundan, sadece bir olacak. Bu durumda, uygulama kodda açıkça beklenmeyen ve işlenmeyen “Bir gün önce” görüntüler. Ekleyerek düzeltilebilir:

if delta == 1:
    return "A day ago"

hesapladıktan hemen sonra delta.

Böceğin tek olumsuz sonucu, bu durumun nasıl olabileceğini merak ederek yarım saatimi boşa harcamam (ve bunun UTC'nin kodda aynı şekilde kullanılmasına rağmen zaman dilimi ile ilgisi olması gerektiğine inanmak) olmasına rağmen, varlığı beni rahatsız ediyor. Bu gösterir ki:

  • Böyle basit bir kaynak kodunda bile mantıksal bir hata yapmak çok kolaydır.
  • Test odaklı gelişme işe yaramadı.

Ayrıca endişe verici, bu tür böceklerin nasıl önlenebileceğini görememem. Kod yazmadan önce daha fazla düşünmenin yanı sıra, düşünebilmemin tek yolu, asla olamayacağımı düşündüğüm davalara pek çok şey eklemek (bir gün önce mutlaka dün olduğuna inandığım gibi) ve sonra her saniye son on yılda, çok karmaşık görünen herhangi bir iddia ihlali olup olmadığını kontrol etmek.

Bu hatayı en başta yaratmaktan nasıl kaçınabilirim?


38
Bunun için bir test davası alarak? Daha sonraları nasıl keşfettiğinize benziyor ve TDD ile ağlar.
Euro

63
Neden sadece teste dayalı bir geliştirme hayranı olmadığımı deneyimlediniz - deneyimlerime göre üretimde yakalanan çoğu hata hiç kimsenin düşünmediği senaryolar. Test odaklı geliştirme ve birim testleri bunlar için hiçbir şey yapmaz. (Birim testler gelecekteki düzenlemelerle ortaya çıkan hataları tespit etmede değere sahiptir.)
Loren Pechtel

102
Benden sonra tekrarlayın: "TDD dahil hiçbir gümüş kurşun yoktur." İşlem yok, kural yok, mükemmel kod üretmek için robotik olarak takip edebileceğiniz algoritma yok. Olsaydı, tüm süreci otomatik hale getirebilir ve bununla yapılabilirdi.
jpmc26

43
Tebrikler, hiçbir testin böcek yokluğunu kanıtlayamayacağına dair eski bilgeliği yeniden keşfettiniz. Ancak, muhtemel girdi alanını daha iyi kapsama alanı oluşturmak için teknikler arıyorsanız, alanın, son durumların ve o alanın denklik sınıflarının kapsamlı bir analizini yapmanız gerekir. TDD teriminden çok önce bilinen tüm eski, iyi bilinen teknikler icat edildi.
Doktor Brown,

80
Sinsice davranmaya çalışmıyorum, ancak sorunuz görünüşte "Düşünmediğim şeyler hakkında nasıl düşünürüm?" Şeklinde yeniden ifade edilebilir. Bunun TDD ile ne alakası olduğundan emin değilim.
Jared Smith,

Yanıtlar:


57

Bunlar, kırmızı / yeşil / refaktörün refaktör aşamasında tipik olarak bulduğunuz hata türleridir. Bu adımı unutma! Aşağıdaki gibi bir refaktör düşünün (test edilmemiş):

def pluralize(num, unit):
    if num == 1:
        return unit
    else:
        return unit + "s"

def convert_to_unit(delta, unit):
    factor = 1
    if unit == "week":
        factor = 7 
    elif unit == "month":
        factor = 30
    elif unit == "year":
        factor = 365
    return delta // factor

def best_unit(delta):
    if delta < 7:
        return "day"
    elif delta < 30:
        return "week"
    elif delta < 365:
        return "month"
    else:
        return "year"

def human_friendly(event_date):
    date = event_date.date()
    today = now.date()
    yesterday = today - datetime.timedelta(1)
    if date == today:
        return "Today"
    elif date == yesterday:
        return "Yesterday"
    else:
        delta = (now - event_date).days
        unit = best_unit(delta)
        converted = convert_to_unit(delta, unit)
        pluralized = pluralize(converted, unit)
        return "{} {} ago".format(converted, pluralized)

Burada daha düşük bir soyutlama seviyesinde 3 fonksiyon yarattınız, bu da izolasyonda test edilmesi daha kolay ve daha kolay. Amaçladığınız bir zaman dilimini dışarıda bırakırsanız, daha basit yardımcı işlevlerde bir boğaz parmağı gibi dışarı çıkar. Ayrıca, çoğaltmayı kaldırarak, hata olasılığını azaltırsınız. Aslında olurdu eklemek kod kırık durumda uygulamaktır.

Diğer daha ince test durumları, bunun gibi yeniden düzenlenmiş bir forma bakarken daha kolay akla geliyor. Örneğin, ne olmalıdır best_unit, yapmanız deltanegatiftir?

Başka bir deyişle, yeniden yapılanma yalnızca güzel yapmak için değildir. Derleyicinin yapamadığı hataları tespit etmeyi kolaylaştırır.


12
Bir sonraki adım uluslararasılaştırılması ve orada pluralizesadece ingilizce kelimelerin bir alt kümesinde çalışmak bir sorumluluk olacaktır.
Deduplicator

@Deduplicator emin, ancak daha sonra hangi dilleri / kültürleri hedeflediğinize bağlı olarak, bir tabloyu veya kaynak dosyadan bir format dizgisini çekmek için sadece pluralizekullanarak numve unitbir çeşit anahtar oluşturarak değişiklik yapabilirsiniz . VEYA farklı birimlere ihtiyaç duyduğunuz için mantığın tamamen yeniden yazılması gerekebilir ;-)
Hulk

4
Bu yeniden yapılandırmada bile bir sorun var, yani "dün" sabahın çok erken saatlerinde anlamlı değil (sabah 12: 01'den kısa bir süre sonra). İnsan dostu olarak, saat 23: 59'da olan bir şey, saat gece yarısını geçtiğinde aniden "bugün" den "dün" ye değişmez. Bunun yerine "1 dakika önce" den "2 dakika önce" ye değişir. "Bugün", birkaç dakika önce olan bir şey açısından çok kaba ve "dün", gece baykuşlarına yönelik problemlerle dolu.
David Hammen

@DavidHammen Bu bir kullanılabilirlik sorunudur ve ne kadar hassas olmanız gerektiğine bağlıdır. En azından saate kadar bilmek istersen, "dün" in iyi olduğunu düşünmezdim. "24 saat önce" çok daha açık ve saat sayısını vurgulamak için yaygın olarak kullanılan bir insan ifadesi. “İnsan dostu” olmaya çalışan bilgisayarlar hemen hemen her zaman bu yanlışı yapıyor ve fazla belirsiz olan “dün” e aşırı yayıyor. Ancak bunu bilmek için, ne düşündüklerini görmek için kullanıcılarla görüşmeniz gerekir. Bazı şeylerde tarih ve saati gerçekten istediğiniz için, “dün” her zaman yanlıştır.
Brandin

149

Test odaklı gelişme işe yaramadı.

Yardım etti gibi gözüküyor, sadece "bir gün önce" senaryosu için bir test yapmadınız. Muhtemelen, bu dava bulunduktan sonra bir test eklediniz; bu hala TDD'dir, bu durumda hatalar bulunursa, hatayı tespit etmek için bir birim sınaması yazarsınız, sonra düzeltirsiniz.

Bir davranış için test yazmayı unutursanız, TDD'nin size yardımcı olacak hiçbir şeyi yoktur; testi yazmayı unutursunuz ve bu nedenle uygulamayı yazmayın.


2
Herhangi bir noktaya göre, geliştirici tdd kullanmamış olsaydı, diğer vakaları da kaçırması daha muhtemel olurdu.
Caleb,

75
Ve bunun üzerine, hatayı düzeltirken ne kadar zaman kazanıldığını bir düşünün? Mevcut testleri uygulayarak, değişikliklerinin mevcut davranışı bozmadığını hemen anladılar. Daha sonra kapsamlı manuel testler yapmak zorunda kalmadan yeni test senaryolarını ve refactor'ü eklemekte özgürdüler.
Caleb,

15
TDD sadece yazılı testler kadar iyidir.
Mindwin 13.01.2018

Başka bir gözlem: bu durum için test eklenmesi, bizi datetime.utcnow()işlevden çıkarmaya zorlayarak ve bunun yerine now(tekrarlanabilir) bir argüman olarak geçmeye zorlayarak tasarımı geliştirecektir .
Toby Speight

114

yirmi altı saat önce gerçekleşen bir olay bir gün önce olacak

Bir problem tanımlanmamışsa testler pek yardımcı olmaz. Takvim günlerini açıkça saatlerce hesaplanan günlerle karıştırıyorsunuz. Takvim günlerine sadık kalırsanız, 1 saat önce, 26 saat önce dün değil . Ve saatlere sadık kalırsanız, o zaman 26 saat önce, süreden bağımsız olarak 1 gün öncesine kadar yuvarlar.


45
Bu yapmak için harika bir nokta. Bir gereksinimin eksik olması, zorunlu olarak, uygulama sürecinizin başarısız olduğu anlamına gelmez. Sadece gereksinimin iyi tanımlanmadığı anlamına gelir. (Ya da sadece zaman zaman olacak olan bir insan hatası yaptınız)
Caleb

Yapmak istediğim cevap bu. Spesifikasyonu "etkinlik bu takvim günüydi, saat olarak delta mevcutsa. Delta'yı belirlemek için başka bir tarih kullanın."
Baldrickk

1
Bu cevabı seviyorum, çünkü asıl sorunu işaret ediyor: zaman ve tarihlerdeki noktalar iki farklı büyüklükte. Onlar birbirleriyle ilişkilidir ama onları karşılaştırmaya başladığınızda, işler çok hızlı bir şekilde güneye gider. Programlamada, tarih ve zaman mantığı doğru olması en zor şeylerden bazılarıdır. Gerçekten pek çok tarih uygulamasının, tarihi temelde 0:00 puan olarak kaydetmesini sevmiyorum. Çok fazla kafa karışıklığı yaratıyor.
Pieter B

38

Yapamazsın TDD, sizi farkında olduğunuz olası sorunlardan korumak konusunda mükemmeldir. Hiç düşünmediğiniz konularla karşılaşırsanız, faydası olmaz. En iyisi, bir başkasının sistemi test etmesini sağlamak;

İlgili okuma: Büyük ölçekli yazılımlar için mutlak sıfır hata durumuna ulaşmak mümkün müdür?


2
Geliştiriciden başka biri tarafından yazılmış testlerin yapılması her zaman iyi bir fikirdir, bu, iki tarafın da hatanın üretime sokması için aynı giriş koşulunu gözden kaçırması gerektiği anlamına gelir.
Michael Kay

35

Yardım edebileceğim normalde aldığım iki yaklaşım var.

İlk önce kenar kasaları arıyorum. Bunlar davranışların değiştiği yerlerdir. Sizin durumunuzda, davranış pozitif tamsayılı günlerin sırası boyunca birkaç noktada değişir. Sıfırda, birde, yedide, vb. Bir kenar kasası vardır. Daha sonra kenar kasalarının etrafına ve etrafına test kılıfları yazardım. -1 gün, 0 gün, 1 saat, 23 saat, 24 saat, 25 saat, 6 gün, 7 gün, 8 gün vs.

Aradığım ikinci şey davranış kalıpları. Haftalar için olan mantığınızda, bir hafta boyunca özel işlemleriniz var. Büyük olasılıkla gösterilmeyen diğer aralıkların her birinde benzer bir mantığa sahipsiniz. Ancak bu mantık günlerce mevcut değil . Bu davanın neden farklı olduğunu doğrulanabilir bir şekilde açıklayana kadar ya da mantığı ekleyene kadar şüphe ile bakardım.


9
Bu, TDD'nin sıklıkla göz ardı edilen ve makale ve rehberlerde nadiren konuştuğumun çok önemli bir parçası - son durumların ve sınır koşullarının test edilmesinde gerçekten önemli - bu durumun% 90'ının kaynağını buluyor. -bir hatalar, aşırı ve
düşükler

2
@GoatInTheMachine - ve bu% 90'lık hataların% 90'ı gün ışığından yararlanma saati geçişi etrafındadır ..... Hahaha
Caleb

1
İlk önce olası girişleri denklik sınıflarına bölebilir ve daha sonra sınıf sınırlarındaki son durumları belirleyebilirsiniz. Bizim için, geliştirme çabasından daha büyük bir çaba olabilir; Buna değip değmeyeceği, yazılımı mümkün olduğunca hatasız teslim etmenin ne kadar önemli olduğuna, son teslim tarihinin ne kadar olduğuna ve ne kadar paranızın ve sabrınızın olduğuna bağlıdır.
Peter - Monica Yeniden

2
Bu doğru cevap. Çok sayıda işletme kuralı, bir dizi değeri, farklı yollarla ele alınabilecekleri aralıklara bölmenizi gerektirir.
abuzittin gillifirca

14

Sen olamaz TDD ile ihtiyaçlarınız mevcut mantıksal hataları yakalamak. Ancak yine de, TDD yardımcı olur. Sonuçta hatayı buldunuz ve bir test davası eklediniz. Fakat temelde, TDD sadece kodun zihinsel modelinize uygun olmasını sağlar. Zihinsel modeliniz hatalıysa, test durumları onları yakalayamaz.

Ancak, hatayı düzeltirken, zaten yaptığınız test durumlarında, hiçbir işlevsel davranışın kırılmadığından emin olun. Bu oldukça önemlidir, bir hatayı düzeltmek kolaydır ancak bir başkasını tanıtmak kolaydır.

Bu hataları önceden bulmak için genellikle denklik sınıfı temelli test durumlarını kullanmaya çalışırsınız. bu prensibi kullanarak, her denklik sınıfından bir vaka seçersiniz, sonra da tüm kenar durumları seçersiniz.

Her bir denklik sınıfından örnekler olarak bugünden, dünden, birkaç gün önce, tam olarak bir hafta önce ve birkaç hafta önce bir tarih seçersiniz. Tarihlerde test ederken, ayrıca testler vermedi emin olur değil sistem tarihini kullanabilirsiniz, ancak karşılaştırma için önceden belirlenmiş tarihi kullanın. Bu aynı zamanda bazı sınır durumları vurgulamak istiyorum: Günün bazı keyfi zamanda testler emin olur, hatta doğrudan doğrudan gece yarısından önce, gece yarısından sonra doğrudan birlikte çalıştırmak ve olacağını at gece yarısı. Bu, her test için, karşı test edildiğinde dört temel zaman olacağı anlamına gelir.

Sonra sistematik olarak diğer tüm sınıflara son vakalar eklerdin. Bugün için sınavın var. Bu yüzden davranıştan hemen önce ve sonra zaman geçmeli ve davranış değişmeli Dün için aynı. Aynı bir hafta önce vb.

Olasılıklar, tüm son durumları sistematik bir şekilde sıralayarak ve onlar için test durumları yazarak, şartnamenizin bir ayrıntıdan mahrum olduğunu bulup eklemenizdir. Taşıma tarihlerinin insanların sık sık yanlış yaptıkları bir şey olduğuna dikkat edin, çünkü insanlar sık ​​sık testlerle çalışabilmelerini sağlamak için sık sık test yaparlar.

Bununla birlikte, yazdıklarımın çoğunun TDD ile ilgisi olmadığını unutmayın. Eşdeğerlik sınıflarını yazmak ve kendi şartnamelerin onlar hakkında yeterince ayrıntılı olduğundan emin olmakla ilgilidir. Mantıksal hataları en aza indirdiğiniz süreç budur . TDD, kodunuzun zihinsel modelinize uygun olmasını sağlar.

Test durumlarıyla gelmek zor . Eşdeğerlik sınıfı temelli test, hepsinin sonu değildir ve bazı durumlarda test vakalarının sayısını önemli ölçüde artırabilir. Gerçek dünyada, tüm bu testleri eklemek genellikle ekonomik olarak uygun değildir (teoride olmasına rağmen yapılmalıdır).


12

Düşünebilmemin tek yolu, asla olmayacağına inandığım davalara (bir gün önce mutlaka dün geldiğine inandığım gibi) davalar için çok fazla iddia eklemek ve ardından son on yıl boyunca her saniye boyunca dolaşmak. Çok karmaşık görünen herhangi bir iddia ihlali.

Neden olmasın? Bu oldukça iyi bir fikir gibi geliyor!

Sözleşmeye sözleşme (iddia) eklemek, doğruluğunu arttırmanın oldukça sağlam bir yoludur. Genellikle olarak ekleyin ön koşullardan işlevi girişindeki ve Hedefşartlar fonksiyon dönüş. Örneğin, bir bütün geri değerler sonşartı ekleyebilir ya "önce bir [birimi]" biçiminde ya da "[sayı] [birimi] önce s". Disiplinli bir şekilde yapıldığında, bu sözleşme ile tasarım yol açar ve yüksek güvence kodunu yazmanın en yaygın yollarından biridir.

Kritik olarak, sözleşmelerin test edilmesi amaçlanmamıştır; Bunlar, testleriniz kadar kodunuzun özellikleridir. Bununla birlikte, sözleşmeler üzerinden test yapabilirsiniz: testinizdeki kodu arayın ve sözleşmelerden hiçbiri hata vermezse, test başarılı olmaz. Son on yılın her saniyesinde ilmek yapmak biraz fazla. Ancak mülkiyete dayalı test denilen başka bir test stilinden faydalanabiliriz .

Kodun belirli çıktılarını test etmek yerine PBT'de, çıktının bazı özelliklere uyduğunu test edersiniz. Örneğin, bir biri mülkiyet reverse()fonksiyonu herhangi liste için olduğunu l, reverse(reverse(l)) = l. Bunun gibi yazma testlerinin yanı sıra, PBT motorunun birkaç yüz rastgele liste (ve birkaç patolojik liste) oluşturmasını ve hepsinin bu özelliğe sahip olup olmadığını kontrol etmesini sağlayabilirsiniz. Varsa yok , motor kodunuzu kırar minimal listesini bulmak için başarısız durumda "küçülür". Ana PBT çerçevesi olarak Hipotezi olan Python'u yazıyorsunuz .

Bu nedenle, aklınıza gelmeyecek daha zor vakaları bulmak için iyi bir yol istiyorsanız, sözleşmeleri ve mülk temelli testleri birlikte kullanmak çok yardımcı olacaktır. Elbette bu, yazı birimi testlerinin yerini almaz, ancak mühendis olarak yapabileceğimizin en iyisi olan, bunu arttırır.


2
Bu, tam olarak bu tür bir sorunun çözümü. Geçerli çıktılar kümesinin tanımlanması kolaydır (normal bir ifadeyi çok basit bir şekilde verebilirsin /(today)|(yesterday)|([2-6] days ago)|...) ve sonra beklenen çıktılar kümesinde olmayan bir tane bulana kadar işlemi rasgele seçilen girdilerle çalıştırabilirsiniz. Bu yaklaşımı alarak ediyorum bu hatayı yakaladı ve olmaz böcek önceden mevcut olabileceğini fark gerektirir.
Jules

@Jules Ayrıca bakınız mülk kontrolü / testi . Genellikle geliştirme sırasında, beklenmeyen durumları ele almak ve genel özellikleri / değişmezleri düşünmeye zorlamak için mülk testleri yapıyorum. Regresyonlar ve
benzerleri

1
Eğer testlerde bu kadar fazla döngü yaparsanız, çok uzun sürecekse, birim testinin temel hedeflerinden birini yitirir: testleri hızlıca yapın !
CJ Dennis,

5

Bu, biraz modülerlik eklemenin faydalı olacağı bir örnektir. Hata eğilimli bir kod bölümü birden çok kez kullanılıyorsa, mümkünse bir işleve sarmak iyi bir uygulamadır.

def time_ago(delta, unit):
    delta_str = _number_to_text(delta) + " " + unit;
    if delta == 1:
        return delta_str + " ago"
    else:
        return delta_str = "s ago"

now = datetime.datetime.utcnow()
today = now.date()
if event_date.date() == today:
    return "Today"

yesterday = today - datetime.timedelta(1)
if event_date.date() == yesterday:
    return "Yesterday"

delta = (now - event_date).days

if delta < 7:
    return time_ago(delta, "day")

if delta < 30:
    weeks = math.floor(delta / 7)
    return time_ago(weeks, "week")

if delta < 365:
    months = math.floor(delta / 31)
    return time_ago(months, "month")

5

Test odaklı gelişme işe yaramadı.

TDD, testleri yazan kişi ağır ise, teknik olarak en iyi şekilde çalışır. İkili programlama yapmıyorsanız bu zordur, bu nedenle düşünmenin başka bir yolu:

  • Test çalışmaları altındaki işlevi onayladığınız gibi onaylamak için testler yazmayın. Kasten kıran testleri yaz.

Bu TDD ile veya TDD olmadan doğru kod yazmak için ve gerçekte kod yazmaktan daha karmaşık bir (belki de fazla değilse) uygulanan farklı bir sanattır. Yapmanız gereken bir şey ve onun için tek, kolay, basit bir cevap yok.

Sağlam yazılım yazmanın temel tekniği, aynı zamanda etkili testlerin nasıl yazıldığını anlamanın temel tekniğidir:

Bir fonksiyonun ön koşullarını - geçerli durumları (yani, fonksiyonun bir metod olduğu sınıfın durumu hakkında hangi varsayımları yaptığınız) ve geçerli girdi parametresi aralıklarını - her veri tipinin bir olası değerleri - alt kümesi olan işleviniz tarafından ele alınacaktır.

İşlev girişindeki bu varsayımları açıkça test etmekten başka bir şey yapmazsanız ve ihlalin kaydedildiğinden veya atıldığından ve / veya daha fazla işlem yapılmadan fonksiyon hatalarının çıkarıldığından emin olmaktan başka bir şey yapmazsanız, yazılımınızın üretimde başarısız olup olmadığını hızlı bir şekilde anlayabilirsiniz. ve hataya tolerans göstererek, zorlayıcı test yazma becerilerinizi geliştirin.


NB. Öncesi ve Sonrası Koşullar, Değişmeyenler ve benzerleri ile ilgili öznitelikleri kullanarak uygulayabilecekleri kütüphaneler hakkında bir literatür vardır. Şahsen ben bu kadar resmi olmanın hayranı değilim, ama araştırmaya değer.


1

Bu, yazılım geliştirme hakkındaki en önemli gerçeklerden biridir: Hatasız kod yazmak kesinlikle, kesinlikle imkansızdır.

TDD, aklınıza gelmeyen test vakalarına karşılık gelen hataları tanıtmaktan kurtarmaz. Ayrıca, farkında olmadan yanlış bir test yazmaktan, daha sonra buggy testini geçmek için yanlış bir kod yazmaktan sizi kurtarmaz. Ve şimdiye kadar yaratılmış olan tüm diğer yazılım geliştirme tekniklerinin benzer delikleri var. Geliştiriciler olarak biz kusurlu insanlarız. Günün sonunda% 100 hatasız kod yazmanın bir yolu yoktur. Asla olmadı ve olmayacak.

Bu, umuttan vazgeçmeniz gerektiğini söylemek değildir. Tamamen mükemmel kod yazmak imkansız olsa da, bu kadar nadir durumlarda ortaya çıkacak yazılımın kullanımı son derece pratik olan çok az hata içeren kod yazmak çok mümkün. Pratikte buggy davranış sergileyen Yazılım yazmak çok mümkündür.

Ancak yazmamız, buggy yazılımı üreteceğimiz gerçeğini benimsememizi gerektirir. Hemen hemen her modern yazılım geliştirme pratiği, böceklerin ilk başta görünmesini engellemek veya kendimizi kaçınılmaz olarak ürettiğimiz hataların sonuçlarından korumak için inşa edilmiş bir düzeydedir:

  • Kapsamlı gereksinimlerin toplanması, kodumuzda yanlış davranışların nasıl göründüğünü bilmemize olanak sağlar.
  • Temiz, dikkatlice tasarlanan kodların yazılması, ilk etapta böceklerin ortaya çıkmamasını ve onları tespit ettiğimizde düzeltmeyi kolaylaştırır.
  • Testler yazmak, yazılımımızdaki olası en kötü hataların çoğunun olacağına inandığımızın bir kaydını oluşturmamızı ve en azından bu hataları önlediğimizi kanıtlamamızı sağlar. TDD bu testleri koddan önce üretir, BDD bu testleri gereksinimlerden türetir ve eski moda birim testi kod yazıldıktan sonra testler üretir, ancak hepsi gelecekteki en kötü gerilemeleri önler.
  • Hakem incelemeleri, her zaman kodun değiştiği, en az iki göz çiftinin kodu gördüğü ve böceklerin master'e ne sıklıkla girdiğini azalttığı anlamına gelir.
  • Bir hata izleyiciyi veya hatalara kullanıcı öyküleri gibi davranan bir kullanıcı öyküsü izleyicisini kullanmak, hataların ortaya çıkması durumunda, sürekli olarak kullanıcıların yollarına girmeleri için unutulmadıkları ve bırakılmadıkları ve takip edildikleri anlamına gelir.
  • Aşamalı bir sunucunun kullanılması, büyük çaplı bir yayından önce, herhangi bir gösteri durdurucu böcekin ortaya çıkma ve bununla baş etme şansının olduğu anlamına gelir.
  • Sürüm kontrolünün kullanılması, en büyük senaryoda, önemli hataların olduğu kodun müşterilere gönderildiği durumlarda, acil durum geri dönüşü gerçekleştirebilir ve işleri çözerken müşterilerinizin ellerine geri güvenilir bir ürün alabileceğiniz anlamına gelir.

Belirlediğiniz soruna nihai çözüm, hatasız kod yazacağınızı garanti etmeyeceğinizi garanti etmek değil, onu kucaklamaktır. Geliştirme sürecinizin tüm alanlarında sektörün en iyi uygulamalarını benimseyin ve kullanıcılarınıza sürekli olarak mükemmel olmasa da, iş için yeterince sağlam olan bir kod iletin.


1

Daha önce bu davayı hiç düşünmediniz ve bu nedenle bunun için bir test vakası yoktu.

Bu her zaman olur ve sadece normaldir. Olası tüm test durumlarını oluşturmak için ne kadar çaba harcadığınız her zaman bir takastır. Tüm test durumlarını değerlendirmek için sonsuz zaman geçirebilirsiniz.

Bir uçak otopilotu için basit bir aletten çok daha fazla zaman harcarsınız.

Genellikle giriş değişkenlerinizin geçerli aralıkları hakkında düşünmenize ve bu sınırları test etmenize yardımcı olur.

Ayrıca, test cihazı geliştiriciden farklı bir kişi ise, çoğu zaman daha önemli vakalar bulunur.


1

(ve UTC'nin kodda aynı şekilde kullanılmasına rağmen zaman dilimleri ile ilgili olduğuna inanmak)

Bu, kodunuzda henüz bir birim sınaması yapmadığınız başka bir mantıksal hata :) - yönteminiz UTC olmayan saat dilimlerindeki kullanıcılar için hatalı sonuçlar döndürür. Hesaplamadan önce hem "şimdi" hem de etkinlik tarihini kullanıcının yerel saat dilimine dönüştürmeniz gerekir.

Örnek: Avustralya'da, bir etkinlik yerel saat 09: 00'da gerçekleşir. UTC tarihi değiştiği için sabah 11'de "dün" olarak gösterilecektir.


0
  • Bir başkasının testleri yazmasına izin verin. Bu şekilde uygulamanıza aşina olmayan biri, düşünmediğiniz nadir durumları kontrol edebilir.

  • Mümkünse, test durumlarını koleksiyon olarak enjekte edin. Bu, başka bir testin eklenmesini, başka bir satır eklemek kadar kolay hale getirir yield return new TestCase(...). Bu, test senaryolarının oluşturulmasını otomatikleştirerek keşif testi yönünde ilerleyebilir : "Kodun bir hafta önce tüm saniye boyunca ne döndüğünü görelim".


0

Tüm testlerinizde başarılı olursa, hiçbir hataya sahip olmadığınızı kabul ediyor gibi görünüyorsunuz. Gerçekte, tüm testleriniz başarılı olursa, bilinen tüm davranışlar doğrudur. Bilinmeyen davranışların doğru olup olmadığını hala bilmiyorsunuz.

Umarım, TDD'nizde kod kapsamı kullanıyorsunuzdur. Beklenmeyen davranış için yeni bir test ekleyin. Ardından, kodda gerçekte hangi yolu geçtiğini görmek için yalnızca beklenmeyen davranış testini çalıştırabilirsiniz. Mevcut davranışı öğrendikten sonra düzeltmek için bir değişiklik yapabilirsiniz ve tüm testler tekrar yapıldığında, doğru bir şekilde yaptığınızı bileceksiniz.

Bu, kodunuzun hatasız olduğu, sadece öncekinden daha iyi olduğu ve bir kez daha bilinen davranışların doğru olduğu anlamına gelmez !

TDD'yi doğru kullanmak, hatasız kod yazacağınız anlamına gelmez, daha az hata yazacağınız anlamına gelir. Diyorsun:

Gereksinimler nispeten açıktı

Bu, gerekliliklerde bir günden fazla, ama dün değil davranışının belirtildiği anlamına mı geliyor? Yazılı bir gereksinimi kaçırdıysanız, bu sizin suçunuz. Gereksinimlerin kodlama sırasında eksik olduğunu fark ettiyseniz, sizin için iyi! Gereksinimler üzerinde çalışan herkes bu davayı kaçırdıysa, diğerlerinden daha kötü olamazsınız. Herkes hata yapar ve ne kadar ince olursa o kadar kolay özlüyorlar. Burdan büyük take TDD olduğunu gelmez önlemek bütün hataları!


0

Böyle basit bir kaynak kodunda bile mantıksal bir hata yapmak çok kolaydır.

Evet. Test odaklı geliştirme bunu değiştirmez. Gerçek kodda ve ayrıca test kodunda hala hata oluşturabilirsiniz.

Test odaklı gelişme işe yaramadı.

Oh, ama oldu! Her şeyden önce, hatayı fark ettiğinizde zaten tüm test çerçevesini uyguladınız ve testteki hatayı düzeltmek zorunda kaldınız (ve gerçek kodu). İkincisi, başlangıçta TDD yapmamış olsaydınız, daha ne kadar böcek yaşamış olacağınızı bilmiyorsunuz.

Ayrıca endişe verici, bu tür böceklerin nasıl önlenebileceğini görememem.

Yapamazsın NASA bile hataları önlemenin bir yolunu bulamadı; biz daha az insan da kesinlikle değil.

Kod yazmadan önce daha fazla düşünmek dışında,

Bu bir yanlışlık. TDD'nin en büyük yararlarından biri, daha az düşünerek kodlayabilmenizdir , çünkü tüm bu testler en azından gerilemeleri iyi yakalar. Ayrıca, hatta, ya da özellikle TDD ile olduğunu değil ilk etapta (veya geliştirme hızı sadece durma noktasına olacaktır) içinde hata içermeyen kodunu vermesi bekleniyor.

düşünebildiğim tek yol, asla olamayacağımı düşündüğüm davalara (bir gün önce mutlaka dün olduğuna inandığım gibi) birçok şey eklemek ve son on yıl boyunca her saniye boyunca dolaşmak Çok karmaşık görünen herhangi bir iddia ihlali.

Bu, şu anda gerçekten ihtiyacınız olanı yalnızca kodlamanın ilkesiyle açıkça çelişir. Bu davalara ihtiyacın olduğunu düşündün, ve öyleydi. Kritik olmayan bir kod parçasıydı; dediğin gibi 30 dakika merak etmen dışında bir zarar gelmedi.

Kritik görev kodları için söylediklerinizi gerçekten yapabilirsiniz ancak günlük standart kodunuz için değil.

Bu hatayı en başta yaratmaktan nasıl kaçınabilirim?

Sen değil. Çoğu regresyon bulmak için testlerinize güvenirsiniz; kırmızı-yeşil-refactor döngüsünü koruyorsunuz, gerçek kodlamadan önce / sırasında testler yazıyorsunuz ve (önemli!) kırmızı-yeşil anahtarını yapmak için gerekli minimum miktarı uyguluyorsunuz (daha az değil). Bu harika bir test kapsamı ile sonuçlanacaktır, en azından olumlu bir sonuç.

Bir hata bulmazsanız, bu hatayı çoğaltmak için bir test yazarsınız ve bu testi kırmızıdan yeşile çevirmek için hatayı en az miktarda çalışarak düzeltirsiniz.


-2

Az önce ne kadar uğraşırsanız çalışın, kodunuzdaki olası tüm hataları asla yakalayamayacağınızı keşfettiniz.

Yani bunun anlamı, bütün böcekleri yakalamaya çalışmak bile boşuna bir alıştırmadır ve bu nedenle TDD gibi teknikleri daha iyi kod yazmanın bir yolu olarak kullanmalısınız, daha az hata içeren kod, 0 hata değil.

Bu da, bu teknikleri kullanarak daha az zaman harcamanız ve zamandan tasarruf etmenizi, geliştirme ağında kaybolan böcekleri bulmak için alternatif yollar üzerinde çalışarak geçirmeniz anlamına gelir.

entegrasyon testi veya bir test ekibi, sistem testi ve bu günlükleri günlüğe kaydetme ve analiz etme gibi alternatifler.

Tüm böcekleri yakalayamıyorsanız, o zaman sizi geçen böceklerin etkilerini azaltmak için bir stratejiniz olmalıdır. Yine de bunu yapmak zorunda kalırsanız, o zaman bu işe daha fazla çaba göstermek, ilk etapta onları durdurmaya çalışmaktan (boşuna) çalışmaktan daha mantıklıdır.

Ne de olsa, zaman yazma testleri için bir servet harcıyor ve ürününüzü müşteriye verdiğiniz ilk gün, özellikle de o hatayı nasıl bulacağınız ve çözeceğinize dair hiçbir ipucunuz yoksa. Ölüm sonrası ve doğum sonrası hata çözümü çok önemlidir ve çoğu kişinin birim testi yazmak için harcadığından daha fazla dikkat gerektirir. Karmaşık bitler için ünite testini saklayın ve önden mükemmelliği denemeyin.


Bu son derece yenilgidir. That in turn means you should spend less time using these techniques- ama daha az hataya yardım edeceğini söyledin mi?
JᴀʏMᴇᴇ

@ JᴀʏMᴇᴇ daha fazla buck.I onlar 10 kat onların koduna mi daha testler yazılı harcama gururluyuz insan tanıyorum için teknik size en bang aldığı bir pragmatik tutum ve hala hatalar var Yani oldukça dogmatik daha duyarlı olduklarından, Test teknikleri hakkında esastır. Entegrasyon testlerinin yine de kullanılması gerekiyor, bu yüzden birim testinden ziyade bunlara daha fazla çaba gösterin.
gbjbaanb
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.