Tahmin edilmesi zor olan kod için birim testleri nasıl yazıyorsunuz?


124

Sıklıkla, bir fonksiyonun kesin sonucunu önceden tahmin etmenin zor olduğu çok sayısal / matematiksel programlarla çalışıyorum.

TDD'yi bu tür bir kodla uygulamaya çalışırken, çoğu zaman test altındaki kodu bu kod için birim testleri yazmaktan çok daha kolay buluyorum, çünkü beklenen sonucu bulmanın tek yolu algoritmayı kendim uygulamaktır. baş, kağıda veya bilgisayardan). Bu doğru gelmiyor, çünkü birim testlerimi doğrulamak yerine test etme kodunu etkili bir şekilde kullanıyorum.

Birim testleri yazmak ve test edilen kodun sonucunu tahmin etmek zor olduğunda TDD uygulamak için bilinen teknikler var mı?

Sonuçları tahmin etmesi zor olan (gerçek) kod örneği:

Günde weightedTasksOnTimeyapılan bir çalışma miktarı workPerDay(0, 24], şimdiki zaman initialTime> 0, ve bir iş listesi taskArray; her biri time> 0, tamamlanma zamanı > 0, son tarih dueve önem değeri importance; [0, 1] aralığında normalize edilmiş bir değer, dueeğer verilen sırayla tamamlanırsa her bir görevden taskArraybaşlayarak başlayarak, görevlerinden önce tamamlanabilecek görevlerin önemini temsil eder initialTime.

Bu işlevi uygulamak için algoritma oldukça basittir: içinde görevler üzerinde yineleme taskArray. Her işlem için, eklemek timeiçin initialTime. Yeni saat <ise due, importancebir aküye ekleyin . Zaman ters workPerDay ile ayarlanır. Akümülatörü iade etmeden önce, normalleştirmek için görev ithalatının toplamına bölün.

function weightedTasksOnTime(workPerDay, initialTime, taskArray) {
    let simulatedTime = initialTime
    let accumulator = 0;
    for (task in taskArray) {
        simulatedTime += task.time * (24 / workPerDay)
        if (simulatedTime < task.due) {
            accumulator += task.importance
        }
    }
    return accumulator / totalImportance(taskArray)
}

Yukarıdaki sorunun basitleştirilebileceğine inanıyorum, çekirdeğini korurken, kaldırma workPerDayve normalleştirme gerekliliklerini yerine getirerek:

function weightedTasksOnTime(initialTime, taskArray) {
    let simulatedTime = initialTime
    let accumulator = 0;
    for (task in taskArray) {
        simulatedTime += task.time
        if (simulatedTime < task.due) {
            accumulator += task.importance
        }
    }
    return accumulator
}

Bu soru, test edilen kodun mevcut bir algoritmanın yeniden uygulanması olmadığı durumları ele almaktadır. Kod bir yeniden uygulama ise, algoritmayı varolan güvenilir uygulamalar doğal bir test oracle gibi davrandığından, sonuçları tahmin etmek kolaydır.


4
Sonuçlarını tahmin etmesi zor olan basit bir fonksiyon örneği verebilir misiniz?
Robert Harvey,

62
FWIW algoritmayı test etmiyorsunuz. Muhtemelen bu doğru. Uygulamayı test ediyorsun. Elle çalışmak genellikle paralel bir yapı olarak iyidir.
Kristian H,


7
Bir algoritmanın makul bir şekilde ünite testi yapılamadığı durumlar vardır - örneğin uygulama süresi birden fazla gün / ay ise. NP Problemlerini çözerken bu olabilir. Bu gibi durumlarda, kodun doğru olduğunu resmi olarak ispatlamak daha uygun olabilir .
Hulk

12
Çok zor sayısal kodlarda gördüğüm bir şey, birim testlerini sadece regresyon testleri olarak ele almak. Fonksiyonu yazın, birkaç ilginç değer için çalıştırın, sonuçları manuel olarak doğrulayın, sonra beklenen sonuçtan regresyonları yakalamak için birim testini yazın. Korku kodlamak mı? Başkalarının ne düşündüğünü merak ediyorum.
Chuu

Yanıtlar:


251

Test edilmesi zor kodda test edebileceğiniz iki şey vardır. İlk olarak, yozlaşmış davalar. Görev dizinizde hiçbir öğe yoksa veya yalnızca bir ya da iki, ancak son teslim tarihi geçmiş, vb. Varsa, ne olur? Gerçek sorununuzdan daha basit, ancak manuel olarak hesaplamak yine de makul olan bir şey.

İkincisi, akıl sağlığı kontrolleri. Bunlar bir cevabın doğru olup olmadığını bilmediğiniz yerlerde yaptığınız kontroller , fakat kesinlikle yanlış olup olmadığını bileceksiniz . Bunlar zamanın ilerlemesi, değerler makul bir aralıkta olmalı, yüzdelerin 100'e kadar eklemesi vb. Gibi şeylerdir.

Evet, bu tam bir test kadar iyi değildir, ancak ne kadar sıklıkla akıl sağlığı kontrolleri ve dejenere vakaları karıştırdığınızı, tam algoritmanızda bir problemi ortaya çıkardığını görünce şaşıracaksınız.


54
Bunun çok iyi bir tavsiye olduğunu düşünüyorum. Bu tür birim testlerini yazarak başlayın. Yazılımı geliştirirken, hatalar veya yanlış cevaplar bulursanız - bunları birim testleri olarak ekleyin. Kesinlikle, doğru cevaplar bulduğunuzda bir dereceye kadar yapın. Onları zamanla biriktirirseniz, (nihayetinde), ne olacağını
bilmemeye

21
Bazı durumlarda yardımcı olabilecek bir başka şey (belki de bu olmasa da) ters bir fonksiyon yazmak ve zincirleme yapıldığında girdi ve çıktılarınızın aynı olduğunu test etmektir.
Cyberspark

7
akıl sağlığı kontrolü, QuickCheck
jk

10
Tavsiye edebileceğim diğer bir test kategorisi ise çıktıdaki istenmeyen değişiklikleri kontrol etmek için birkaç tane. Beklenen sonucu elde etmek için kodun kendisini kullanarak bunları aldatabilirsiniz, çünkü bunların amacı, çıktı nötr bir değişiklik olarak tasarlanan bir şeyin istemeden algoritmik davranışı etkilediğini işaretleyerek bakıcılara yardımcı olmaktır.
Dan Neely

5
@iFlo Şaka yaptığından emin değilim, ama tersi zaten var. Testin başarısız olduğunu ters işlevde bir sorun olabileceğini fark etmeye değer
lucidbrot

80

Tahmin edilmesi zor çıktılarla bilimsel yazılım için testler yazıyordum. Metamorfik İlişkileri çok kullandık. Temelde, kesin sayısal çıktıları bilmeseniz bile, yazılımınızın nasıl davranması gerektiği hakkında bildiğiniz şeyler vardır.

Durumunuz için olası bir örnek: eğer her gün yapabileceğiniz iş miktarını azaltırsanız, yapabileceğiniz toplam iş miktarı en iyi şekilde aynı kalır, ancak muhtemelen azalır. Bu nedenle, işlevi bir dizi değer için çalıştırın ve workPerDayilişkinin tuttuğundan emin olun.


32
Metamorfik ilişkiler genel olarak böyle durumlar için yararlı bir araç olan özellik bazlı testlerin özel bir örneğidir
Dannnno

38

Diğer cevaplar, uç veya hata durumları için testler geliştirmek için iyi fikirlere sahiptir. Diğerleri için, algoritmanın kendisini kullanmak ideal değildir (açıkçası) ama yine de kullanışlıdır.

Algoritmanın (veya buna bağlı verinin) değişip değişmediğini algılar.

Değişiklik bir kazaysa, bir taahhüt geri alabilirsiniz. Değişiklik kasıtlıysa, birim testini tekrar ziyaret etmeniz gerekir.


6
Ve kayıt için, bu tür testlere genellikle amaçlarına göre "regresyon testleri" denir ve temelde herhangi bir değişiklik / yeniden düzenleme için bir güvenlik ağıdır.
Pac0,

21

Başka bir kod türü için birim testleri yazdığınız gibi:

  1. Bazı temsili test durumları bulun ve bunları test edin.
  2. Son vakaları bulun ve bunları test edin.
  3. Hata koşullarını bulun ve bunları test edin.

Kodunuz rastgele bir öğe içermiyorsa veya deterministik değilse (yani aynı girdiyle aynı çıktıyı üretmez), test edilebilir bir birimdir.

Yan etkilerden veya dış kuvvetlerden etkilenen fonksiyonlardan kaçının. Saf fonksiyonların test edilmesi daha kolaydır.


2
Deterministik olmayan algoritmalar için, RNG tohumunu kaydetmek veya işlem sırası veya düşük tutarsızlık determinitistic dizi örn kullanılarak ya taklit Halton dizisi
Wondra

14
O algoritmanın çıkışını kontrol etmek imkansız değilse @PaintingInAir, algoritma bile olabilir olmak yanlış?
WolfgangGroiss,

5
Unless your code involves some random elementBuradaki hile rastgele sayı üretecinizi enjekte edilmiş bir bağımlılık yapmaktır, böylece istediğiniz kesin sonucu veren bir sayı üreteci ile değiştirebilirsiniz. Bu, tekrar doğru bir şekilde test etmenizi sağlar - üretilen sayıları giriş parametreleri olarak da sayın. not deterministic (i.e. it won't produce the same output given the same input)Birim testinin kontrollü bir durumdan başlaması gerektiğinden , ancak daha sonra enjekte edebileceğiniz rastgele bir elemente sahipse belirleyici olmayabilir. Burada başka olasılıklar düşünemiyorum.
Flaters

3
@PaintingInAir: Ya da. Benim yorumum hem hızlı hem de hızlı test yazımı için geçerlidir. Tek bir örneği el ile hesaplamanız üç gün sürerse (kodu kullanmayan en hızlı yöntemi kullandığınızı varsayalım) - o zaman üç gün ne gerekiyorsa o olur. Bunun yerine beklenen test sonucunu gerçek kodun kendisine dayandırırsanız, test kendini tehlikeye atıyor demektir. Bu yapmak gibi if(x == x), anlamsız bir karşılaştırma. İki sonucunuza ( gerçek : koddan gelir ; beklenen : dış bilginizden gelir) birbirinden bağımsız olmak için ihtiyacınız olur.
Flater

2
Belirleyici olmasa bile yine de test edilebilir, şartnamelere uygun olması ve uyumluluğun ölçülebilmesi (örneğin rasgele dağıtım ve yayılması) Anomali riskini ortadan kaldırmak için çok sayıda örnek gerekebilir.
mckenzm

17

Yayınlanan yorumlar nedeniyle güncelleme

Orijinal cevap, kısalık aşkına kaldırıldı - düzenleme geçmişinde bulabilirsiniz.

PaintingInAir Bağlam için: bir girişimci ve akademik olarak, tasarladığım algoritmaların çoğu kendimden başka biri tarafından istenmiyor. Soruda verilen örnek, bir görev sırasının kalitesini en üst düzeye çıkarmak için türevsiz bir optimize edicinin bir parçasıdır. Örnek işlev ihtiyacını dahili olarak nasıl tanımladığım konusunda: "Zamanında tamamlanan görevlerin önemini en üst düzeye çıkarmak için nesnel bir işleve ihtiyacım var". Bununla birlikte, bu talep ile birim testlerinin uygulanması arasında büyük bir boşluk olduğu görülmektedir.

Birincisi, uzunca bir cevap vermemek için bir TL;

Bunu şu şekilde düşünün:
Bir müşteri McDonald's'a girer ve bir tost makinesi olarak marul, domates ve el sabunu içeren bir burger ister. Bu sipariş, burgeri tam istediği gibi yapan aşçıya verilir. Müşteri bu burgeri alıyor, onu yiyor ve sonra aşçıya bunun lezzetli bir burger olmadığını söylüyor!

Bu aşçının suçu değil - yalnızca müşterinin açıkça sorduğu şeyi yapıyor. İstenen siparişin gerçekten lezzetli olup olmadığını kontrol etmek aşçı işi değil . Aşçı, sadece müşterinin sipariş ettiği şeyi yaratır. Lezzetli buldukları bir şeyi sipariş etmek müşterinin sorumluluğundadır .

Benzer şekilde, algoritmanın doğruluğunu sorgulamak geliştiricinin işi değildir. Onların tek işi algoritmayı istenen şekilde uygulamak.
Birim testi, geliştiricinin bir araçtır. Burger'in siparişi karşıladığını doğrular (mutfaktan çıkmadan önce). Sipariş edilen burgerin aslında lezzetli olduğunu onaylamaya çalışmaz (ve etmemelidir).

Hem müşteri hem de aşçı olsanız bile , aşağıdakiler arasında anlamlı bir ayrım var:

  • Bu yemeği düzgün hazırlayamadım, lezzetli değildi (= yemek hatası). Bonfile sevseniz bile, yanık bifteği asla iyi tadamaz.
  • Yemeğimi doğru hazırladım ama hoşuma gitmiyor (= müşteri hatası) Eğer biftek sevmiyorsanız, mükemmellik için pişirmiş olsanız bile biftek yemekten asla hoşlanmayacaksınız.

Buradaki ana sorun, müşteri ile geliştirici (ve analist - arasında bir rol yapmamak) olmasına rağmen, bu rol geliştirici tarafından da gösterilebilir.

Kodu test etme ve işletme gereksinimlerini test etme arasında ayrım yapmanız gerekir.

Örneğin, müşteri [this] gibi çalışmasını istiyor . Bununla birlikte, geliştirici yanlış anlar ve [o] kodunu yazar .

Geliştirici nedenle olmadığını test birim testleri yazacak [yani] beklendiği gibi çalışır. Uygulamayı doğru geliştirmişse, başvuruyu müşterinin beklediği [bunu] yapmasa bile birim testleri geçecektir .

Müşterinin beklentilerini (iş gereksinimleri) test etmek istiyorsanız, bunun ayrı (ve daha sonra) bir adımda yapılması gerekir.

Bu sınamaların ne zaman yapılması gerektiğini size gösteren basit bir geliştirme iş akışı:

  • Müşteri çözmek istedikleri sorunu açıklar.
  • Analist (veya geliştirici) bunu bir analizde yazar.
  • Geliştirici, analizin açıkladığı şeyi yapan bir kod yazar.
  • Geliştirici , analizi doğru takip edip etmediğini görmek için kodunu test eder (birim testleri)
  • Ünite testleri başarısız olursa, geliştirici tekrar geliştirmeye gider. Ünite tüm testleri geçene kadar bu işlem süresiz olarak gerçekleşir.
  • Şimdi, test edilmiş (onaylanmış ve başarılı) bir kod tabanına sahip olan geliştirici uygulamayı oluşturur.
  • Uygulama müşteriye verilir.
  • Müşteri şimdi , kendisine verilen başvurunun gerçekten çözmek istediği sorunu çözüp çözmediğini test eder (KG testleri) .

Müşteri ile geliştirici aynı olduğunda iki ayrı test yapmanın ne anlama geldiğini merak edebilirsiniz. Geliştiriciden müşteriye "el atma" olmadığından, testler birbiri ardına gerçekleştirilir, ancak yine de ayrı adımlar uygulanır.

  • Birim testleri, geliştirme aşamanızın bitip bitmediğini doğrulamanıza yardımcı olan özel bir araçtır.
  • QA testleri uygulama kullanılarak yapılır .

Algoritmanızın kendisinin doğru olup olmadığını test etmek istiyorsanız, bu geliştiricinin işinin bir parçası değildir . Bu müşterinin endişesidir ve müşteri uygulamayı kullanarak bunu test edecektir .

Bir girişimci ve akademik olarak, burada farklı sorumlulukları vurgulayan önemli bir ayrım eksik olabilir.

  • Uygulama müşterinin başlangıçta sorduğuna uymazsa, kodda sonradan yapılacak değişiklikler genellikle ücretsiz yapılır ; bu bir geliştirici hatası olduğundan. Geliştirici bir hata yaptı ve düzeltmenin bedelini ödemek zorunda.
  • Uygulama müşterinin ilk başta istediğini yaparsa, ancak müşteri fikrini değiştirdi (örneğin farklı ve daha iyi bir algoritma kullanmaya karar verdiniz), kod tabanındaki değişiklikler , müşteriye aittir , çünkü geliştiricinin hatası, müşterinin şimdi istediklerinden farklı bir şey istemiş olması. Fikrini değiştirmek müşterinin sorumluluğundadır (maliyeti) ve bu nedenle geliştiricilerin önceden kararlaştırılmayan bir şeyi geliştirmek için daha fazla çaba harcamasını sağlamak.

"Algoritmayı kendiniz bulursanız" durumu hakkında daha fazla ayrıntı görmekten mutlu olurum, çünkü sorunların ortaya çıkması en muhtemel durumdur. Özellikle “eğer A sonra B, yoksa C” örnekleri verilmediği durumlarda. (ps ben downvoter değilim)
PaintingInAir

@PaintingInAir: Ama durumunuza bağlı olduğu için bu konuda gerçekten ayrıntılı olarak çalışamam. Bu algoritmayı oluşturmaya karar verdiyseniz, belli bir özellik sağlamak için bunu açıkça yaptınız. Bunu yapmanı kim istedi? İsteğini nasıl tarif ettiler? Size belirli senaryolarda neler olması gerektiğini söylediler mi? (bu bilgiler cevabımda "analiz" olarak adlandırdığım şeydir) Aldığınız her türlü açıklama (algoritmayı oluşturmanıza neden olan), algoritmanın istenen şekilde çalışıp çalışmadığını test etmek için kullanılabilir. Kısacası, kod / kendi oluşturduğunuz algoritma dışında her şey kullanılabilir.
Fla

2
@PaintingInAir: Müşteriyi, analisti ve geliştiriciyi sıkıca bağlamak tehlikelidir; Sorunun başlangıç noktasını tanımlamak gibi temel adımları atlamaya meyilli olduğunuzdan . Burada yaptığınız şeyin bu olduğuna inanıyorum. Doğru şekilde uygulanıp uygulanmadığı yerine algoritmanın doğruluğunu test etmek istiyor gibisiniz . Ama öyle yapmıyorsun. Uygulamanın test edilmesi birim testleri kullanılarak yapılabilir. Algoritması kendisi Test meselesidir kullanarak sonuçlarını denetimi gerçeği sizin (test) uygulaması ve - (o kadar bu gerçek test sizin kod temeli kapsamı dışındadır olmalıdır ).
Flater

4
Bu cevap zaten muazzam. Orijinal içeriği yeniden biçimlendirmenin bir yolunu bulmayı denemenizi şiddetle öneririz, böylece atmak istemiyorsanız, içeriği yeni cevaba entegre edebilirsiniz.
jpmc26

7
Ayrıca, öncülüne katılmıyorum. Testler, kodun spesifikasyona göre yanlış bir çıktı oluşturduğunu kesinlikle göstermelidir. Bazı bilinen test durumlarının çıktılarını doğrulamak için testler için geçerlidir. Ayrıca, aşçı "el sabunu" nu geçerli bir hamburger maddesi olarak kabul etmekten daha iyisini bilmelidir ve işveren aşçıyı hangi malzemelerin mevcut olduğu konusunda neredeyse kesinlikle eğitmiştir.
jpmc26

9

Mülkiyet Testi

Bazen matematiksel işlevler, geleneksel örnek tabanlı birim testlerinden ziyade "Özellik Testi" ile daha iyi hizmet vermektedir. Örneğin, bir tamsayı "çarpma" fonksiyonu gibi birimler için birim testleri yazdığınızı düşünün. Fonksiyonun kendisi çok basit görünse de, eğer çoğalmanın tek yolu bu ise, fonksiyonun içindeki mantık olmadan nasıl iyice test edersiniz? Beklenen giriş / çıkışlara sahip dev tablolar kullanabilirsiniz, ancak bu sınırlıdır ve hataya açıktır.

Bu gibi durumlarda, belirli beklenen sonuçları aramak yerine, işlevin bilinen özelliklerini test edebilirsiniz. Çarpma için, negatif bir sayının ve pozitif sayının çarpılmasının negatif bir sayıyla sonuçlanması gerektiğini ve iki negatif sayının çarpılmasının pozitif bir sayıyla sonuçlanması gerektiğini biliyor olabilirsiniz. Test değerleri bu fonksiyonları test etmek için iyi bir yoldur. Genel olarak birden fazla özellik için test yapmanız gerekir, ancak her durumda beklenen sonucu mutlaka bilmeden, bir fonksiyonun doğru davranışını doğrulayan bir sınırlı özellik kümesi tanımlayabilirsiniz.

Gördüğüm Mülkiyet Testi ile ilgili en iyi tanıtımlardan biri de F # ' dır . Umarım sözdizimi, tekniğin açıklamasını anlamak için bir engel değildir.


1
Örneğin, rastgele dörtlüler (a, b, c) oluşturmak ve (ab) (cd) veriminin (ac-ad) - (bc-bd) olduğunu onaylamak gibi, örneğinizde yeniden çarpma işleminize biraz daha spesifik bir şeyler eklemenizi öneririm. Bir çarpma işlemi oldukça bozulabilir ve (negatif negatif zaman negatif sonuçları) kuralını hala koruyabilir, ancak dağıtıcı kural belirli sonuçları öngörür.
supercat

4

Kodu yazmak ve ardından sonucun "doğru görünüp görünmediğini" görmek cazip gelir, ancak haklı olarak düşündüğünüz gibi, bu iyi bir fikir değildir.

Algoritma zor olduğunda, sonucun elle hesaplanmasını kolaylaştırmak için birçok şey yapabilirsiniz.

  1. Excel'i kullanın. Sizin için hesaplamanın bir kısmını veya tamamını yapan bir elektronik tablo oluşturun. Adımları görebilmeniz için yeterince basit tutun.

  2. Yönteminizi her biri kendi testleriyle daha küçük test edilebilir yöntemlere ayırın. Küçük parçaların çalıştığından emin olduğunuzda, bir sonraki adımda manuel olarak çalışmak için bunları kullanın.

  3. Akıl sağlığı kontrolü için toplu özellikler kullanın. Örneğin, bir olasılık hesaplayıcınız olduğunu varsayalım; bireysel sonuçların ne olacağını bilmiyor olabilirsiniz, ancak hepsinin% 100'e kadar eklemesi gerektiğini biliyorsunuz.

  4. Kaba kuvvet. Tüm olası sonuçları üreten bir program yazın ve hiçbirinin algoritmanızın ürettiğinden daha iyi olmadığını kontrol edin.


3. için, burada bazı yuvarlama hatalarına izin verin. Toplam tutarınızın% 100,000001 veya benzer şekilde yakın fakat kesin olmayan rakamlar olması olasıdır.
Flater

2
4 hakkında tam olarak emin değilim. Olası tüm girdi kombinasyonları için optimal sonucu üretebiliyorsanız (test onayını almak için kullanırsınız), o zaman doğal olarak zaten en uygun sonucu hesaplayabilir ve bu nedenle Test etmeye çalıştığın bu ikinci kod başına ihtiyacım yok . Bu noktada, halihazırda çalıştığı kanıtlanmış olan mevcut optimum sonuç jeneratörünüzü kullanmaktan daha iyi olursunuz. (ve henüz işe yaradığı kanıtlanmadıysa, başlamak için testlerinizi kontrol etmek için sonucuna güvenemezsiniz).
Flater

6
Genellikle, kaba kuvvetin karşılamadığı doğruluk kadar başka gereksinimler de vardır. örneğin performans.
Ewan

1
@ flater Eğer buna inanıyorsanız, sıralama, en kısa yol, satranç motoru vb. kullanmaktan nefret ediyorum. Ama kimliğinizi yuvarlama hatasında tamamen kumar oynamak tüm gün kumarhaneye izin
Ewan

3
Bir kral piyonu sona erdirmek oyununa başladığınızda, flater istifa eder misiniz? çünkü bütün oyun kaba bir şekilde zorlanamadığı için ayrı bir pozisyon olamayacağı anlamına gelmez. Sırf kaba kuvvetleri bir ağa doğru en kısa yolu zorlamanız, tüm ağlardaki en kısa yolu bildiğiniz anlamına gelmez
Ewan

2

TL; DR

Diğer cevaplarda bulunmayan tavsiyeler için "karşılaştırmalı test" bölümüne gidin.


baş

Algoritmanın reddetmesi gereken durumları ( workPerDayörneğin sıfır veya negatif ) ve önemsiz durumları (örneğin, boş tasksdiziler) test ederek başlayın .

Bundan sonra, ilk önce en basit durumları test etmek istersiniz. İçin tasksgiriş, farklı uzunlukları test etmek gerekir; 0, 1 ve 2 elementin test edilmesi yeterlidir (2 bu test için "çok" kategorisine ait).

Zihinsel olarak hesaplanabilecek girdileri bulabilirseniz, bu iyi bir başlangıçtır. Bazen kullandığım bir teknik, istenen bir sonuçtan başlamak ve bu sonucu üretmesi gereken girdilere geri dönmek (spesifikasyonda).

Karşılaştırmalı test

Bazen çıkışın girişle ilişkisi açık değildir, ancak bir giriş değiştirildiğinde farklı çıkışlar arasında öngörülebilir bir ilişki vardır . Örneği doğru anladıysam, bir görev eklemek (diğer girdileri değiştirmeden) asla zamanında yapılan iş oranını asla yükseltmez, bu nedenle işlevi iki kez çağıran bir test oluşturabiliriz - bir kez ve bir kez ekstra görev olmadan - ve iki sonuç arasındaki eşitsizliği ortaya koyar.

geri dönüşün

Bazen, elle hesaplanmış bir sonucu, belirtime karşılık gelen adımlarla gösteren uzun bir yorum yapmak zorunda kaldım (böyle bir yorum genellikle test durumundan daha uzundur). En kötü durum, daha önceki bir uygulamayla uyumluluğunu farklı bir dilde veya farklı bir ortamda sürdürmeniz gerektiğidir. Bazen test verilerini benzer bir şekilde etiketlemeniz gerekir /* derived from v2.6 implementation on ARM system */. Bu pek tatmin edici değildir, ancak taşıma sırasında bir sadakat testi veya kısa süreli bir koltuk değneği olarak kabul edilebilir.

Hatırlatmalar

Bir testin en önemli özelliği okunabilirliğidir - eğer girdiler ve çıktılar okuyucuya opaksa, test çok düşük bir değere sahipse, ancak okuyucu aralarındaki ilişkileri anlamaya yardım ederse, test iki amaca hizmet eder.

Yanlış sonuçlar için (örneğin kayan nokta) uygun bir "yaklaşık-eşittir" kullanmayı unutmayın.

Aşırı sınamadan kaçının - yalnızca diğer sınamaların erişemediği bir şeyi (sınır değeri gibi) içeriyorsa sınama ekleyin.


2

Bu tür test edilmesi zor bir işlev için çok özel bir şey yoktur. Aynısı, harici arayüzleri kullanan kodlar için de geçerlidir (örneğin, kontrolünüz altında olmayan ve kesinlikle test takımınız tarafından test edilmeyen 3. parti bir uygulamanın REST API’si veya dönüş değerlerinin tam bayt formatı).

Algoritmanızı bazı akıllıca girdiler için basitçe çalıştırmak, ne olduğunu görmek, sonucun doğru olduğundan emin olmak ve girişi ve sonucu bir test durumu olarak kapsüllemek oldukça geçerli bir yaklaşımdır. Bunu birkaç durum için yapabilir ve böylece birkaç örnek alabilirsiniz. Giriş parametrelerini olabildiğince farklı hale getirmeye çalışın. Harici bir API çağrısı olması durumunda, gerçek sisteme karşı birkaç çağrı yapar, bunları bir araçla izler ve ardından programınızın nasıl tepki verdiğini görmek için birim testinize atarsınız; görev planlama kodunuzun çalıştırılması, el ile doğrulanması ve ardından testlerde sonucun kodlanması.

Ardından, açık bir şekilde, (örneğinizde) boş bir görevler listesi; Bunun gibi şeyler.

Test takımınız sonuçları kolayca tahmin edebileceğiniz bir yöntem kadar iyi olmayabilir; ancak yine de test paketinden (veya sadece bir duman testinden)% 100 daha iyi

Sorunun olsa, bunu zor bulmak olduğunu karar sonucu olmadığını ise doğru, o zaman bu tamamen farklı bir sorundur. Örneğin, keyfi olarak çok sayıda sayının asal olup olmadığını belirleyen bir yönteminiz olduğunu varsayalım. Rastgele herhangi bir sayıya zar zor atabilir ve ardından sonuç doğruysa sadece "bak" (kafanızdaki veya bir kağıt parçasındaki en yüksekliğe karar veremeyeceğinizi varsayarsak). Bu durumda yapabileceğiniz çok az şey var - bilinen sonuçları (yani bazı büyük astarları) almanız veya işlevselliği farklı bir algoritmayla (belki de farklı bir ekip bile - NASA'ya düşkün gibi) uygulamanız gerekir. Bu) ve umarım eğer her iki uygulama da bir hata ise, en azından hata aynı yanlış sonuçlara yol açmaz.

Bu sizin için normal bir durumsa, gereksinim mühendislerinizle iyi bir konuşma yapmanız gerekir. Gereksinimlerinizi, sizi kontrol etmenin kolay olduğu (veya mümkün olduğu kadar) formüle edemezlerse, o zaman bitip bitmediğinizi ne zaman anlarsınız?


2

Diğer cevaplar iyidir, o zamana kadar topluca kaçırdıkları bazı noktalara ulaşmaya çalışacağım.

Sentetik Açıklık Radarı (SAR) kullanarak görüntü işlemesi için yazılım yazdım (ve tamamen test ettim). Doğada bilimsel / sayısal (bir sürü geometri, fizik ve matematik var).

Birkaç ipucu (genel bilimsel / sayısal testler için):

1) Ters çevrmeleri kullanın. Ne var fftiçinde [1,2,3,4,5]? Fikrim yok. Nedir ifft(fft([1,2,3,4,5]))? Olmalı [1,2,3,4,5](veya buna yakınsa, kayan nokta hataları ortaya çıkabilir). 2B durum için de aynı şey geçerli.

2) Bilinen delilleri kullanın. Bir determinant işlevi yazarsanız, determinantın rastgele bir 100x100 matrisinin ne olduğunu söylemek zor olabilir. Fakat kimlik matrisinin determinantının 100x100 olsa bile 1 olduğunu biliyorsunuz. Ayrıca, fonksiyonun tersinir olmayan bir matriste 0 döndürmesi gerektiğini de biliyorsunuz (100x100 tam 0'larla dolu).

3) Kesin varsayımlar yerine kaba armalar kullanın . Bahsedilen SAR işlemi için, görüntüler arasında bir eşleme yaratan bağlanma noktaları oluşturarak ve sonra onları eşleştirmeleri için aralarında çözgü yapan iki görüntü kaydedecek bazı kodlar yazdım. Alt piksel düzeyinde kayıt olabilir. Bir priori, iki görüntünün kaydının nasıl olabileceği hakkında bir şey söylemek zor . Nasıl test edebilirsiniz? Gibi şeyler:

EXPECT_TRUE(register(img1, img2).size() < min(img1.size(), img2.size()))

yalnızca çakışan kısımlara kaydolabileceğiniz için, kayıtlı görüntünün en küçük görüntünüze eşit veya daha küçük olması gerekir ve ayrıca:

scale = 255
EXPECT_PIXEL_EQ_WITH_TOLERANCE(reg(img, img), img, .05*scale)

kendisine kaydedilen bir görüntünün kendisine KAPALI olması gerektiğinden, ancak eldeki algoritma nedeniyle kayan nokta hatalarından biraz daha fazlasını yaşayabilirsiniz, bu nedenle yalnızca her pikselin piksellerin alabileceği aralığın +/-% 5'i içinde olduğunu kontrol edin (0-255 görüntü işlemede yaygın olan gri tonlamalıdır). Sonuç, en azından giriş ile aynı boyutta olmalıdır.

Sadece duman testi bile yapabilirsiniz (örneğin, onu arayın ve çarpmadığından emin olun). Genel olarak, bu teknik, sonucun (kolayca) test edilemeyen bir priori hesaplanamadığı daha büyük testler için daha iyidir.

4) RNG'niz için rastgele bir sayı tohumu olan OR STORE kullanın.

Skor yok tekrarlanabilir olması gerekir. Ancak, yeniden üretilebilir bir işlem elde etmenin tek yolunun rastgele sayı üretecine belirli bir tohum sağlamaktır. Bazen rastgelelik testi değerlidir. Rasgele üretilen dejenere vakalarda ortaya çıkan bilimsel koddaki hataları gördüm / duydum (karmaşık algoritmalarda dejenere durumun ne olduğunu bile görmek zor olabilir)). Fonksiyonunuzu her zaman aynı tohumla çağırmak yerine, rastgele bir tohum oluşturun ve ardından bu tohumu kullanın ve tohumun değerini kaydedin. Bu şekilde, her koşunun farklı bir rastgele tohumu vardır, ancak bir çarpma olursa, hata ayıklamak için giriş yapmış olduğunuz tohumu kullanarak sonucu tekrar çalıştırabilirsiniz. Aslında bunu pratikte kullandım ve bir böceğe çarptı, ben de söyleyeceğimi düşündüm. Kuşkusuz bu sadece bir kez oldu ve her zaman yapmaya değmeyeceğinden eminim, bu yüzden bu tekniği sağduyulu kullanın. Aynı tohum ile rastgele olsa da, her zaman güvenlidir. Dezavantajı (her zaman sadece aynı tohumu kullanmak yerine): Test çalışmalarınızı kaydetmeniz gerekir. Upside: Doğruluk ve hata ayıklama.

Senin özel durum

1) Boş bir değerin 0 döndürdüğünü test edin taskArray (bilinen onay).

2) bu şekilde rasgele giriş oluşturma task.time > 0 , task.due > 0, ve task.importance > 0 tüm task s, ve sonuç daha büyük olan öne 0 (kaba assert, rasgele giriş) . Delirmeye ve rastgele tohumlar oluşturmanıza gerek yok, algoritmanız sadece onu garanti edecek kadar karmaşık değil. Ödenmesi muhtemel 0 ihtimal var: testi basit tut.

3) Her s için test yapın , sonra sonuç (bilinen iddia)task.importance == 0 task 0

4) Buna değinilen diğer cevaplar, ancak sizin özel durumunuz için önemli olabilir : Ekibiniz dışındaki kullanıcılar tarafından tüketilecek bir API yapıyorsanız, dejenere vakaları test etmeniz gerekir. Örneğin, eğer workPerDay == 0, kullanıcıya geçersiz giriş olduğunu söyleyen hoş bir hata attığınızdan emin olun. Eğer bir API yapmıyorsanız, bu sadece sizin ve ekibiniz için, muhtemelen bu adımı atlayabilir ve sadece dejenere vaka ile çağırmayı reddedebilirsiniz.

HTH.


1

Algoritmanızın özellik tabanlı testi için onay testini birim test takımınıza dahil edin. Belirli bir çıktıyı kontrol eden birim testleri yazmaya ek olarak, ana kodtaki onaylama hatalarını tetikleyerek başarısız olmak için tasarlanmış testler yazın.

Pek çok algoritma, algoritmaların aşamaları boyunca belirli özelliklerin korunmasına yönelik doğruluk kanıtlarına güvenir. Bir fonksiyonun çıktısına bakarak bu özellikleri makul bir şekilde kontrol edebiliyorsanız, özelliklerinizi test etmek için yalnızca ünite testi yeterli olacaktır. Aksi takdirde, iddiaya dayalı test, algoritmanın her aldığında bir uygulamanın bir özellik koruduğunu test etmenizi sağlar.

İddiaya dayalı test, algoritma kusurlarını, kodlama hatalarını ve sayısal dengesizlik gibi sorunlardan kaynaklanan uygulama hatalarını ortaya çıkaracaktır. Pek çok dilde, derleme sırasında veya kodun yorumlanmasından önce iddiaları soyan mekanizmalar vardır, böylece üretim modunda çalıştırıldığında iddialar performans cezasına çarptırılmaz. Kodunuz birim testlerini geçerse ancak gerçek hayattaki bir durumda başarısız olursa, iddiaları tekrar hata ayıklama aracı olarak açabilirsiniz.


1

Buradaki diğer cevapların bazıları çok iyi:

  • Test tabanı, kenar ve köşe kılıfları
  • Akıl sağlığı kontrolleri gerçekleştirin
  • Karşılaştırmalı testler yap

... birkaç başka taktik daha eklerdim:

  • Sorunu çözün.
  • Algoritmayı kodun dışında ispatla.
  • [Harici olarak kanıtlanmış] algoritmanın tasarlandığı gibi uygulandığını test edin.

Ayrıştırma algoritması bileşenlerinin yapmasını beklediğiniz şeyi yapmalarını sağlar. Ve "iyi" bir ayrıştırma, onların birbirine düzgün şekilde yapıştırıldığından emin olmanızı da sağlar. Bir Büyük ayrışma genelleştirir ve ölçüde algoritmayı kolaylaştırır yapabilirsiniz kapsamlı testler yazmak için yeterince iyi elle (basitleştirilmiş, jenerik algoritma (ler) in) sonuçları tahmin.

Bu ölçüde ayrışamıyorsanız, algoritmayı kodun dışında, sizi ve meslektaşlarınızı, paydaşlarınızı ve müşterilerinizi tatmin etmek için ne gerekiyorsa yapın. Ve sonra, uygulamanızın tasarımla eşleştiğini kanıtlayacak kadar ayrıştırın.


0

Bu biraz idealist bir cevap gibi görünebilir ancak farklı test türlerini tanımlamaya yardımcı olur.

Eğer uygulama için katı cevaplar önemliyse, algoritmayı tanımlayan şartlarda gerçekten örnekler ve beklenen cevaplar verilmelidir. Bu gereklilikler grup gözden geçirilmeli ve aynı sonuçları alamazsanız, sebebi tanımlamanız gerekir.

Analistin yanı sıra uygulayıcı rolünü oynuyor olsanız bile, gerçekte gereksinimler yaratmalı ve birim testleri yazmadan çok önce gözden geçirmelisiniz, bu durumda beklenen sonuçları bilmeniz ve testlerinizi buna göre yazmanız gerekir.

Öte yandan, bu, iş mantığının bir parçası olmayan veya bir iş mantığı cevabını desteklemeyen bir parçaysa, sonuçların ne olduğunu görmek için testi çalıştırmak ve beklemek için testi değiştirmek iyi olmalıdır. bu sonuçlar. Son sonuçlar, gereksinimlerinize göre zaten kontrol edilmiştir, eğer doğrularsa, o zaman bu son sonuçları besleyen tüm kodların sayısal olarak doğru olması gerekir ve bu noktada ünite testleriniz, verilen bir durumu kanıtlamak yerine son arıza durumlarını ve gelecekteki yeniden düzenleme değişikliklerini tespit etmek için daha fazladır. algoritma doğru sonuçlar üretir.


0

Süreci takip etmek vesilesiyle tamamen kabul edilebilir olduğunu düşünüyorum:

  • bir test çantası tasarlayın
  • cevabınızı almak için yazılımınızı kullanın
  • cevabı elle kontrol et
  • Bir regresyon testi yazın, böylece yazılımın gelecekteki sürümleri bu cevabı vermeye devam edecektir.

Bu, bir cevabın doğruluğunu elle kontrol etmenin cevabı ilk prensiplerden elde etmekten daha kolay olduğu her durumda makul bir yaklaşımdır.

Yazdırılan sayfaları oluşturmak için yazılım yazan ve yazdırılan sayfada tam olarak doğru piksellerin ayarlandığını kontrol eden testler biliyorum. Bunu yapmanın tek mantıklı yolu, sayfayı oluşturmak için kodu yazmak, iyi göründüğünü gözle kontrol etmek ve ardından sonucu gelecek sürümler için bir regresyon testi olarak yakalamaktır.

Sadece bir kitapta okuduğunuzda, belirli bir metodolojinin önce test senaryolarını yazmayı teşvik ettiği, her zaman bu şekilde yapmak zorunda kaldığınız anlamına gelmez. Kurallar ihlal edilmek üzere.


0

Diğer cevapların cevaplarında, belirli bir sonuç test edilen fonksiyonun dışında tespit edilemediğinde bir testin nasıl göründüğüne ilişkin teknikler zaten vardır .

Ek olarak, diğer cevaplarda görmediğim şeyleri de bir şekilde otomatik testler yapmak:

  1. 'Rastgele' girişler
  2. Veri aralıkları arasında yineleme
  3. Sınır gruplarından test vakalarının yapılması
  4. Yukarıdakilerin tümü.

Örneğin, fonksiyon her biri izin verilen giriş aralığı [-1,1] olan üç parametre alırsa, her bir parametrenin tüm kombinasyonlarını test edin, {-2, -1.01, -1, -0.99, -0.5, -0.01, 0,0.01 , 0,5,0,99,1,1,01,2, (-1,1) 'te biraz daha rastgele

Kısacası: Bazen düşük kaliteli miktar sübvanse edilebilir.

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.