Yol kapsamı tüm hataları bulmayı garanti ediyor mu?


64

Bir program boyunca her yol test edilirse, bu tüm hataları bulmayı garanti ediyor mu?

Değilse neden olmasın? Program akışının olası her bir kombinasyonundan nasıl geçtiniz ve varsa sorunu bulamıyor musunuz?

"Bütün böceklerin" bulunabileceğini önermek için tereddüt ediyorum, ama belki de bunun yolu, kapsama alanı pratik olduğu için (birleşimsel olduğu gibi), bu yüzden hiç yaşanmamış mı?

Not: Bu makale , düşündüğüm gibi kapsama alanı türlerinin kısa bir özetini sunar.


33
Bu, durma problemine eşdeğerdir .

31
Ya olması gereken kod oradaysa?
RemcoGerlich

6
@Snowman: Hayır, değil. Durma problemini tüm programlar için çözmek mümkün değildir, ancak birçok özel program için çözülebilir. Bu programlar için, tüm kod yolları sınırlı bir sürede (muhtemelen uzun olsa da) sayılabilir.
Jørgen Fogh

3
@ JørgenFogh Ancak herhangi bir programda hata bulmaya çalışırken, programın durup durmadığı önceden bilinmeyen bir şey değil mi? Bu soru , "herhangi bir programdaki tüm hataları yol kapsamı yoluyla bulma" genel yöntemi hakkında değil mi? Bu durumda, "herhangi bir programın durup durmayacağını bulmak" ile aynı değil mi?
Andres F.

1
@AndresF. Programın , içinde yazıldığı dilin alt kümesinin durmayan bir programı ifade edebilmesi durumunda durması durumunda bilinmemektedir . Programınız sınırlandırılmamış döngüler / özyineleme / setjmp vb. Kullanmadan C ile veya Coq veya ESSL ile yazılırsa, durması gerekir ve tüm yollar izlenebilir. (Turing-bütünlüğü ciddi olarak abartılıyor)
Leushenko

Yanıtlar:


128

Bir program boyunca her yol test edilirse, bu tüm hataları bulmayı garanti ediyor mu?

Hayır

Değilse neden olmasın? Program akışının olası her bir kombinasyonundan nasıl geçtiniz ve varsa sorunu bulamıyor musunuz?

Çünkü tüm olası yolları test etseniz bile , bunları tüm olası değerlerle veya tüm olası değer kombinasyonlarıyla test etmediniz . Örneğin (sözde kod):

def Add(x as Int32, y as Int32) as Int32:
   return x + y

Test.Assert(Add(2, 2) == 4) //100% test coverage
Add(MAXINT, 5) //Throws an exception, despite 100% test coverage

Program testinin böceklerin varlığını ikna edici bir şekilde gösterebildiğine, ancak bunların bulunmadığını asla gösteremediğine dikkat çektiğinden yirmi yıl geçti . Bu kamuoyuna açıklanacak sözünü açık bir şekilde aktardıktan sonra, yazılım mühendisi günün sırasına geri döner ve tıpkı krizokosmik saflaştırmalarını daraltmaya devam eden eski zaman simyacısı gibi test stratejilerini iyileştirmeye devam eder.

- EW Dijkstra (Vurgu eklendi. 1988'de yazıldı. Şimdi 2 yıldan fazla oldu.)


7
@ digitgopher: Sanırım bir programın girişi yoksa, ne işe yarar ki?
Mason Wheeler,

34
Ayrıca, entegrasyon testlerinin eksik olması, testlerde hataların, bağımlılıklarda hataların, yapı / dağıtım sistemindeki hataların veya orijinal şartname / gereksinimlerde hata bulunma olasılığı da vardır. Tüm hataları bulma konusunda hiçbir zaman garanti veremezsiniz .
Ixrec

11
@Ixrec: SQLite, yine de oldukça cesur bir çaba gösteriyor! Ama ne kadar büyük bir çaba olduğuna bakın! Bu, büyük kod tabanlarına iyi ölçeklendirilemez.
Mason Wheeler

13
Tüm olası değerleri veya bunların kombinasyonlarını test etmekle kalmaz, bazılarının yarış koşullarını ortaya koyan tüm göreli zamanlamaları test etmediniz ya da testinizi bir çıkmaza sokar, bu da herhangi bir şeyi rapor etmemesini sağlar . Başarısızlık bile olmaz!
Idonotexist,

14
Benim hatırladığım ( bunun gibi yazılarla desteklenmiş ) Dijkstra'nın iyi programlama uygulamalarında, bir programın doğru olduğuna dair kanıtın (her koşulda) programın gelişiminin ayrılmaz bir parçası olması gerektiğine inandığı yönündedir. Bu açıdan bakıldığında, test olan simya gibi. Abartı yerine, bunun çok güçlü bir dille ifade edilen çok güçlü bir görüş olduğunu düşünüyorum.
David K,

71

Ek olarak Mason'ın cevap , aynı zamanda başka bir sorun vardır: kapsama yok değil kod test edildi ne diyeceğim, bu kod ne söyler idam .

% 100 yol kapsama alanına sahip bir testiteniz olduğunu hayal edin. Şimdi tüm iddiaları kaldırın ve testsuite tekrar çalıştırın. Voilà, testsuite hala% 100 yol kapsama alanına sahip, ancak kesinlikle hiçbir şeyi test etmiyor.


2
Test edilen kodu çağırırken bir istisna olmadığından emin olabilir (testteki parametrelerle). Bu hiç olmamasından biraz daha fazla.
Palo Ebermann

7
@ PaŭloEbermann Anlaşıldı, hiç yoktan biraz fazla. Ancak, “tüm hataları bulmaktan” muazzam derecede daha az;)
Andres F.

1
@ PaŭloEbermann: İstisnalar bir kod yoludur. Kod atabilir ancak belirli test verileriyle atılmazsa, test% 100 yol kapsamı elde etmez. Bu, bir hata işleme mekanizması olarak istisnalara özel değildir. Visual Basic'in ON ERROR GOTOC de olduğu gibi bir yol da if(errno).
MS 31.05'te

1
@ MSalters Girdi ne olursa olsun (şartname ile) herhangi bir istisna atmaması gereken koddan bahsediyorum. Herhangi bir atarsa, bu bir hata olurdu. Elbette, bir istisna atmak için belirtilen bir kodunuz varsa, test edilmesi gerekir. (Ve tabii ki, Jörg’in dediği gibi, sadece kodun bir istisna atmadığını kontrol etmek, atmayan bir kod için bile doğru olanı yapmak için genellikle yeterli değildir.) Ve bazı istisnalar da sıfır işaretçi serbest bırakma veya sıfıra bölme gibi görünmez kod yolu. Yol kapsama aracınız bunları yakalar mı?
Paŭlo Ebermann,

2
Bu cevap onu işaret ediyor. Talebi daha da ileri götürür ve bundan dolayı yol kapsamının tek bir hatayı bile bulmayı garanti etmediğini söylerdim. En azından değişikliklerin tespit edileceğini garanti edebilecek ölçütler var, ancak - mutasyon testi aslında kodun (bazı) değişikliklerinin tespit edileceğini garanti edebilir .
eis

34

İşte işleri yuvarlamak için daha basit bir örnek. Aşağıdaki sıralama algoritmasını düşünün (Java'da):

int[] sort(int[] x) { return new int[] { x[0] }; }

Şimdi test edelim:

sort(new int[] { 0xCAFEBABE });

Şimdi, (A) bu özel çağrının sortdoğru sonucu döndürdüğünü, (B) tüm kod yollarının bu test tarafından kapsandığını düşünün .

Ancak, açıkçası, program aslında sıralama değil.

Programda hiçbir hata bulunmadığını garanti etmek için tüm kod yollarının kapsamının yeterli olmadığını izler.


12

absBir sayının mutlak değerini döndüren işlevi düşünün . İşte bir test (Python, bazı test çerçevelerini hayal edin):

def test_abs_of_neg_number_returns_positive():
    assert abs(-3) == 3

Bu uygulama doğru, ancak yalnızca% 60 kod kapsamı alıyor:

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

Bu uygulama yanlış, ancak% 100 kod kapsamı alıyor:

def abs(x):
    return -x

2
: İşte (non-linebroken Python af ediniz) testini geçer başka uygulamasıdır def abs(x): if x == -3: return 3 else: return 0Muhtemelen elide olabilir else: return 0bölümünü ve% 100 kapsama almak ama işlev birim testi geçmek olsa bile esasen yararsız olacaktır.
CVn

7

Mason'un cevabına bir başka ilave olarak , bir programın davranışı çalışma zamanının ortamına bağlı olabilir.

Aşağıdaki kod bir Ücretsiz Kullanım Sonrası içerir:

int main(void)
{
    int* a = malloc(sizeof(a));
    int* b = a;
    *a = 0;
    free(a);
    *b = 12; /* UAF */
    return 0;
}

Bu kod Tanımsız Davranış, yapılandırmaya bağlı olarak (release | debug), işletim sistemi ve derleyici farklı davranışlar sağlayacaktır. Yalnızca yol kapsamı UAF'yi bulacağınızı garanti etmez, ancak test takımınız tipik olarak yapılandırmaya bağlı olarak UAF'ın çeşitli olası davranışlarını kapsamaz.

Başka bir kayda göre, yol kapsamı tüm hataları bulmayı garanti etse bile, pratikte herhangi bir programda gerçekleştirilebilmesi olası değildir. Şunu düşünün:

int main(int a, int b)
{
    if (a != b) {
        if (cryptohash(a) == cryptohash(b)) {
            return ERROR;
        }
    }
    return 0;
} 

Test takımınız bunun için tüm yolları oluşturabiliyorsa, tebrikler siz bir kriptografisiniz.


Yeterince küçük tamsayılar için kolay :)
CodesInChaos

Hakkında hiçbir şey bilmeden cryptohash, "yeterince küçük" olduğunu söylemek biraz zor. Belki bir hesap makinesinde tamamlamak iki gün sürer. Ama evet, intbiraz olabilir short.
dureuill

32 bit tamsayılar ve tipik şifreleme karma değerleri (SHA2, SHA3, vb.) İle hesaplama oldukça ucuz olmalıdır. Birkaç saniye ya da öylesine.
CodesInChaos

7

Diğer cevaplardan, testlerde% 100 kod kapsamının% 100 kod doğruluğu anlamına gelmediği veya testlerde bulunabilecek tüm hataların bulunabileceği anlamına gelmediği açıktır (hiçbir testin yakalayamayacağı hataları dikkate almayın).

Bu soruyu cevaplamanın başka bir yolu pratikten biridir:

Gerçek dünyada ve gerçekten de kendi bilgisayarınızda,% 100 kapsama alanı sağlayan ve hala daha iyi testlerin tanımlayabileceği hatalar da dahil olmak üzere hataları olan bir dizi test kullanılarak geliştirilen birçok yazılım parçası bulunmaktadır.

Bu nedenle gerekli bir soru şudur:

Kod kapsamı araçlarının amacı nedir?

Kod kapsamı araçları, bir kişinin test etmeyi ihmal ettiği alanları tanımlamaya yardımcı olur. Bu iyi olabilir (kod test olmadan bile doğru bir şekilde doğrudur) çözülmesi imkansız olabilir (bir nedenden dolayı bir yola girilemez) ya da şimdi veya gelecekteki değişiklikleri takip eden büyük bir kokuşmuş hatanın yeri olabilir.

Bazı yönlerden yazım denetimi karşılaştırılabilir: Bir şey yazım denetimini "geçebilir" ve sözlükteki bir kelimeyle eşleşecek şekilde yanlış yazılabilir. Veya doğru kelimeler sözlükte olmadığından "başarısız olabilir". Ya da geçip saçma olabilir. Yazım denetimi, prova okumanızda kaçırmış olabileceğiniz yerleri tanımlamanıza yardımcı olan bir araçtır, ancak tam ve doğru prova okumayı garanti edemediğinden, kod kapsamı tam ve doğru testi garanti edemez.

Ve tabii ki yazım denetimini kullanmanın yanlış yolu ünlüdür, her öneriye ewe denizi ile gitmek, ördeğin daha da kötüleşmesini ve eğer öyleyse kredi bıraktığını gösterir.

Kod kapsamı dahilinde, özellikle de% 98'e yakın mükemmele sahipseniz, kalan yolları etkilemek için davaları doldurmak cazip gelebilir.

Bu, yazım denetimi dikme ile eşleştirmenin, tüm kelimelerin hava ya da düğüm olduğunu uygun kelimelerdir. Sonuç ördek yavrusu karmaşasıdır.

Ancak, kapsanmayan yolların gerçekte neye ihtiyaç duyduğunu test ederseniz, kod kapsama aracı işini yapar; size doğruluk vaadinde değil, yapılması gereken bazı işleri işaret ediyor.


+1 Bu yanıtı beğendim, çünkü yapıcı ve kapsama alanındaki bazı avantajlardan söz ediyor.
Andres F.

4

Yol kapsamı, gerekli tüm özelliklerin uygulanıp uygulanmadığını size söyleyemez. Bir özellikten çıkmak bir hatadır, ancak yol kapsamı bunu algılamayacaktır.


1
Bunun bir hatanın tanımına bağlı olduğunu düşünüyorum. Eksik özelliklerin veya işlevlerin hata olarak kabul edilmesi gerektiğini düşünmüyorum.
eis

@eis - dokümantasyonu aslında X yaptığını söylemediği bir ürünle ilgili bir sorun görmüyor musunuz? Bu "bug" un oldukça dar bir tanımı. Borland'ın C ++ ürün serisi için KG'yi yönettiğimde o kadar cömert değildi.
Pete Becker,

Bu asla uygulanmadıysa, belgelerin neden X yaptığını anlamıyorum
eis

@ eis - eğer özgün tasarım X için çağrılan orijinal tasarım, dokümantasyon X özelliğini açıklarsa sona erebilir. Eğer kimse uygulamadıysa, bu bir hatadır ve yol kapsamı (veya başka bir kara kutu testi) bulamaz.
Pete Becker

Hata! Yol kapsama alanı kara kutu değil beyaz kutu testi . Beyaz kutu testi eksik özellikleri yakalayamıyor.
Pete Becker,

4

Sorunun bir kısmı,% 100 kapsamın yalnızca kodun tek bir işlemden sonra doğru şekilde çalışacağını garanti etmesidir . Bellek sızıntısı gibi bazı hatalar görünmeyebilir veya tek bir yürütmeden sonra sorun çıkartabilir, ancak zamanla uygulama için sorunlara neden olabilir.

Örneğin, bir veritabanına bağlanan bir uygulamanız olduğunu varsayalım. Belki de bir yöntemde programcı, sorgularını yaptıklarında veritabanına olan bağlantıyı kapatmayı unutur. Bu yöntem üzerinde birkaç test çalıştırabilir ve işlevselliği ile ilgili herhangi bir hata bulamayabilirsiniz, ancak veritabanı sunucunuz uygun bağlantıların olmadığı bir senaryoyu çalıştırabilir, çünkü bu özel yöntem yapıldığında bağlantıyı kapatmadı ve açık bağlantılar şimdi zaman aşımı.


Bu konunun bir parçası olduğunu kabul etti, ancak asıl konu bundan daha temel. Sınırsız hafızalı ve eşzamanlılık olmayan teorik bir bilgisayarda bile,% 100 test kapsamı hata bulunmadığı anlamına gelmez. Bunun önemsiz örnekleri, buradaki cevaplarda boldur, ama işte bir diğeri: eğer programım times_two(x) = x + 2, bu tamamen test paketi tarafından ele alınacak assert(times_two(2) == 4), ancak bu açıkça açıkçası bir kod! Bellek sızıntılarına gerek yok :)
Andres F.

2
Bu harika bir nokta ve bunun hatasız uygulamaların tabutunda daha büyük / daha temel bir çivi olduğunu kabul ediyorum, ancak söylediğiniz gibi buraya zaten eklenmiş ve tamamen kaplanmamış bir şey eklemek istedim. mevcut cevaplar. Veritabanı bağlantıları artık ihtiyaç duyulmadığında tekrar bağlantı havuzuna bırakılmadığı için çöken uygulamaları duydum - Bir bellek sızıntısı sadece kaynak yanlış yönetiminin kanonik bir örneğidir. Amacım, kaynakların genel olarak uygun şekilde yönetilmesinin tamamen test edilemeyeceğini eklemek oldu.
Derek W

İyi bir nokta. Kabul.
Andres F.

3

Bir program boyunca her yol test edilirse, bu tüm hataları bulmayı garanti ediyor mu?

Daha önce de söylediğim gibi, cevap HAYIR.

Değilse neden olmasın?

Söylenenlerin yanı sıra, farklı düzeylerde ortaya çıkan ve birim testleriyle test edilemeyen hatalar var. Sadece birkaç söz:

  • entegrasyon testlerine yakalanan hatalar (ünite testleri sonuçta gerçek kaynakları kullanmamalıdır)
  • gereksinimlerdeki hatalar
  • tasarım ve mimaride hatalar

2

Test edilecek her yol için ne anlama geliyor?

Diğer cevaplar harika, ama sadece "bir program aracılığıyla her yolun test edildiği" durumunun belirsiz olduğunu eklemek istiyorum.

Bu yöntemi düşünün:

def add(num1, num2)
  foo = "bar"  # useless statement
  $global += 1 # side effect
  num1 + num2  # actual work
end

Bunu iddia eden bir test yazarsanız add(1, 2) == 3, bir kod kapsamı aracı size her satırın kullanıldığını söyleyecektir. Fakat aslında küresel yan etki ya da işe yaramaz atama hakkında hiçbir şey iddia etmediniz. Bu satırlar yürütüldü, ancak gerçekten test edilmedi.

Mutasyon testi bu gibi sorunları bulmanıza yardımcı olur. Bir mutasyon test aracı, kodu "mutasyona geçirmek" ve testlerin hala geçip geçmediğini görmek için önceden belirlenmiş bir yol listesine sahip olacaktır. Örneğin:

  • Bir mutasyon değişebilir +=için -=. Bu mutasyon test başarısızlığına neden olmaz, bu nedenle testinizin küresel yan etki hakkında anlamlı bir şey iddia etmediğini kanıtlar.
  • Başka bir mutasyon ilk satırı silebilir. Bu mutasyon test başarısızlığına neden olmaz, bu nedenle testinizin ödev için anlamlı bir şey iddia etmediğini kanıtlar.
  • Yine başka bir mutasyon üçüncü satırı silebilir. Bu, bir testin başarısız olmasına neden olur; bu durumda, testinizin bu satır hakkında bir şey iddia ettiğini gösterir.

Özet olarak, mutasyon testleri, testlerinizi test etmenin bir yoludur . Ancak, asıl işlevi hiçbir zaman mümkün olan her girdi grubuyla test etmeyeceğiniz gibi, olası her mutasyonu asla çalıştırmayacaksınız, bu nedenle, bu sınırlıdır.

Yapabileceğimiz her test, hatasız programlara doğru ilerlemek için sezgiseldir. Hiçbir sey mükemmel değildir.


0

Şey ... evet aslında, her yol “geçilirse” program test edilir. Ancak bu, tüm değişkenler dahil olmak üzere programın sahip olabileceği tüm olası durumların tüm alanı boyunca olası her yol anlamına gelir. Oldukça basit, statik olarak derlenmiş bir program için bile - eski bir Fortran sayı kırıcısı - bu en azından düşünülebilecek olsa da mümkün değildir: sadece iki tamsayılı değişkeniniz varsa, temelde noktaları bağlamak için tüm olası yollarla uğraşıyorsunuzdur. iki boyutlu bir ızgara; Aslında Seyahat Satış elemanı gibi görünüyor. For n böyle değişkenler, bir uğraştığımız n boyutlu uzayda, bu nedenle herhangi bir gerçek program için, görev tamamen kolay işlenebilir olduğunu.

Daha da kötüsü: ciddi şeyler için, yalnızca belirli sayıda ilkel değişkene sahip değilsiniz , aynı zamanda fonksiyon çağrıları sırasında değişkenler yaratın ya da değişken boyut değişkenleri ... ya da bunun gibi bir Turing-complete dilinde mümkün olan herhangi bir değişken yaratın. Bu durum, uzaysal alanı sonsuz boyutta yapar ve saçma bir şekilde güçlü test ekipmanları verilse bile tüm kapsama alanını ümit eder.


Dedi ki ... aslında işler pek de kasvetli değil. İse mümkün proove doğru olduğu bütün programları, ancak birkaç fikir vazgeçmek gerekecek.

İlk olarak: bildirimsel bir konuşmaya geçmeniz şiddetle tavsiye edilir. Zorunlu diller, bir nedenden ötürü, her zaman en popüler olanlardır, ancak algoritmaları gerçek dünya etkileşimleriyle bir araya getirme şekilleri , “doğru” ile ne demek istediğinizi söylemeyi bile zorlaştırır .

Tamamen işlevsel programlama dillerinde çok daha kolay : bunlar matematiksel işlevlerin gerçek ilginç özellikleri ile gerçekte hiçbir şey söyleyemeyeceğiniz bulanık gerçek dünya etkileşimleri arasında açık bir ayrım yapar . İşlevler için, “doğru davranış” tanımlaması çok kolaydır: tüm olası girişler için (bağımsız değişken türlerinden) karşılık gelen istenen sonuç çıkarsa, işlev doğru davranır.

Şimdi, bunun hala inatçı olduğunu söylüyorsunuz ... sonuçta, olası tüm argümanların alanı da genel olarak sonsuz boyuttadır. Doğru - tek bir işlev için, naif kapsama testi bile, zorunlu bir programda beklediğinizden çok daha fazlasını sağlar! Bununla birlikte, oyunu değiştiren inanılmaz güçlü bir araç var: evrensel niceleme / parametrik polimorfizm . Temel olarak, bu, çok genel veri türlerine fonksiyon yazmanıza olanak tanır, verinin basit bir örneği için çalışırsa, mümkün olan herhangi bir girdi için çalışacağını garanti eder.

En azından teorik olarak. Bunu gerçekten kanıtlayabilmeniz için gerçekten genel olan doğru tipleri bulmak kolay değildir - genellikle, bağımlı bir şekilde yazılmış bir dile ihtiyacınız vardır ve bunların kullanımı oldukça zordur. Ancak, parametrik polimorfizm ile işlevsel bir tarza sahip tek başına yazmak, zaten “güvenlik seviyenizi” büyük ölçüde artırıyor - tüm böcekleri mutlaka bulamayacaksınız, ancak derleyiciyi görememeleri için onları oldukça iyi saklamanız gerekecek!


İlk cümlesine katılmıyorum. Programın her aşamasından geçmek kendi içinde herhangi bir hatayı tespit etmiyor . Çarpışmaları ve açık hataları kontrol etseniz bile, asıl işlevselliği hiçbir şekilde kontrol etmediniz, bu nedenle hata alanının yalnızca küçük bir kısmını kapladınız.
Matthew

@MatthewRead: Bunu uygularsanız, “hata alanı” tüm durumların alanlarının uygun bir alt alanıdır. Elbette varsayımsaldır, çünkü “doğru” durumlar bile herhangi bir ayrıntılı teste izin veremeyecek kadar büyük bir alan oluşturur.
leftaroundabout
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.