6. Hibakeresés, debugging
6.5. A hibák leegyszerűsítése
A hibakeresésnek ezen fázisa azt tűzi ki célul, hogy a reprodukált hibát leegyszerűsítse egy olyan teszt-esetté, ami csak a releváns információkat tartalmazza. Ez azt jelenti, hogy a teszt-esetben csak azok, és pontosan azok az információk vannak, amik szükségesek ahhoz, hogy a hiba előforduljon.
A probléma minden egyes jellemzőjére ellenőriznünk kell, hogy releváns-e a probléma előfordulásának szempontjából. Ha nem, akkor egyszerűen kihagyjuk a probléma leírásából.
6.5.1. Módszer
Egyfajta lehetőség a Kernighan and Pike (1999) által javasolt bináris keresés, ami a következőképpen működik:
Az input felét hagyjuk el. Ha a hiba nem áll fent, akkor lépjünk egy lépést vissza, és hagyjuk el a másik felét az inputnak.
Ezt a módszert általánosítsuk a következőképpen:
Legyen egy test(c) függvényünk, ami kap egy c inputot, és eldönti, hogy a kérdéses hiba előfordul-e (x), nem fordul elő (), vagy valami más történik (?). Tegyük fel, hogy van egy hibát generáló inputunk (cx), amit kétfelé tudunk osztani (c1 és c2). Ekkor három dolog történhet:
1. A cx input első felének eltávolítása után továbbra is fennáll a hiba, vagyis test(cx\c1) = x. Ekkor folytathatjuk a keresést egy új c’x = cx\c1
inputtal.
2. Az előző pont nem teljesülése esetén, ha cx input második felének eltávolítása után továbbra is fennáll a hiba (vagyis test(cx\c2) = x ), akkor folytassuk az új c’x = cx\c2 inputtal.
3. Az előző két pont nem teljesülése esetén osszuk kisebb részekre az eredeti cx
inputot (finomítjuk az algoritmust).
A 3-as eset miatt általánosítanunk kell az előtte lévő részt is, vagyis: ha cx -et n
részhalmazra bontjuk (c1,…,cn), akkor:
• Ha valamelyik részhalmaz eltávolításakor továbbra is fennáll a hiba ( test(cx\ci) = x, valamely i Є {1, …, n}-re), akkor folytassuk c’x = cx\ci, és n’=max(n – 1, 2).
• Különben folytassuk c’x = cx, és n’=2n. Ha cx-et nem lehet tovább bontani, akkor kész vagyunk.
Mivel a program futását befolyásoló tényezők nem csak inputok lehetnek (hanem pl.
idő, kommunikáció, szál-kezelés, stb.), ezért az algoritmust tovább általánosíthatjuk
„jellemzőkre” (circumstances). A jellemzők egy halmazát nevezzük konfigurációnak.
Formálisan a ddmin algoritmus a következőképpen néz ki:
• A program futását befolyásoló jellemző-halmazt nevezzük el konfigurációnak. Az összes jellemző halmazát jelöljük C-vel
• Legyen a test: 2C → {x, , ?} egy tesztelő függvény, ami egy c ⊆ C konfigurációról eldönti, hogy egy adott hiba előfordul (x), nem fordul elő (), vagy nem mondható meg(?).
• Legyen cx egy „elbukó” konfiguráció, vagyis cx ⊆ C, ahol test(cx)= x, és legyen a test függvény kimenete sikeres, ha egy jellemzőt se adunk meg, vagyis:
test(Ø) =
• A minimalizáló delta debuggoló algoritmus, ddmin(cx) minimalizálja a hibát generáló cx konfigurációt. Egy olyan c’x konfigurációt ad eredményül, amire teljesülnek az alábbiak
o c’x ⊆ cx
o test(c’x) = x
o c’x egy releváns konfiguráció, vagyis egyetlen egy jellemzőt sem lehet kivenni c’x -ből úgy, hogy a hiba eltűnjön.
• A ddmin algoritmust a következőképpen definiáljuk: ddmin(c’x) = ddmin’(c’x, 2), ahol ddmin’(c’x, n)-re teljesülnek az alábbiak:
o ddmin’(c’x, n) = c’x, ha |c’x| = 1
o ddmin’(c’x,n) = ddmin’(c’x\ci,max(n–1,2)) különben, ha van olyan
i Є {1..n} × test(c’x\ci) = x
o ddmin’(c’x, n) = ddmin’(c’x, min(2n, |c’x|)) különben, ha n <|c’x|
o ddmin’(c’x, n) = c’x különben, ahol
c’x=c1 c2 … cn úgy, hogy minden ci,cj ×ci ∩cj =Ø és |ci|≈|cj| teljesül.
• A ddmin’ előfeltétele, hogy test(c’x) = x és n ≤ | c’x |.
Az algoritmus optimalizálható az alábbi opciók szerint:
• Cache használata – mivel egy konfigurációt többször is tesztelünk.
• Korai leállítás (időkorlát, darabolási egység, előrehaladás alapján)
• Szintaktikus egyszerűsítés – Nem karakterek szerint, hanem nagyobb egységek szerint történik az egyszerűsítés (lexikális szinten).
6.5.2. Példa
Az alábbiakban látható a ddmin algoritmusra egy példa. Egy XML alapú adatfeldolgozó program hibásan működik az egyik tesztesetre, míg egy másikra helyesen. A két teszteset között a különbség egyetlen paraméterezett tag: amelyik tesztesetben ez benne van, az bukik, amelyikből hiányzik, az helyesen lefut. A ddmin algoritmusunk így a következőképpen működik:
Input:
<SELECT NAME=”priority” MULTIPLE SIZE=7> - 40 karakter – Eredmény: x
<SELECT NAME=”priority” MULTIPLE SIZE=7> - 0 karakter – Eredmény:
Lépésszám Input Karakterszám Eredmény 1 <SELECT NAME=”priority” MULTIPLE SIZE=7> 20
2 <SELECT NAME=”priority” MULTIPLE SIZE=7> 20
3 <SELECT NAME=”priority” MULTIPLE SIZE=7> 30
4 <SELECT NAME=”priority” MULTIPLE SIZE=7> 30 x
5 <SELECT NAME=”priority” MULTIPLE SIZE=7> 20
6 <SELECT NAME=”priority” MULTIPLE SIZE=7> 20 x
7 <SELECT NAME=”priority” MULTIPLE SIZE=7> 10
8 <SELECT NAME=”priority” MULTIPLE SIZE=7> 10
9 <SELECT NAME=”priority” MULTIPLE SIZE=7> 15
10 <SELECT NAME=”priority” MULTIPLE SIZE=7> 15
11 <SELECT NAME=”priority” MULTIPLE SIZE=7> 15 x
12 <SELECT NAME=”priority” MULTIPLE SIZE=7> 10
13 <SELECT NAME=”priority” MULTIPLE SIZE=7> 10
14 <SELECT NAME=”priority” MULTIPLE SIZE=7> 10
15 <SELECT NAME=”priority” MULTIPLE SIZE=7> 12
16 <SELECT NAME=”priority” MULTIPLE SIZE=7> 13
17 <SELECT NAME=”priority” MULTIPLE SIZE=7> 12
18 <SELECT NAME=”priority” MULTIPLE SIZE=7> 13 x
19 <SELECT NAME=”priority” MULTIPLE SIZE=7> 10
20 <SELECT NAME=”priority” MULTIPLE SIZE=7> 10
21 <SELECT NAME=”priority” MULTIPLE SIZE=7> 11
22 <SELECT NAME=”priority” MULTIPLE SIZE=7> 10 x
23 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
24 <SELECT NAME=”priority” MULTIPLE SIZE=7> 8
25 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
26 <SELECT NAME=”priority” MULTIPLE SIZE=7> 8
27 <SELECT NAME=”priority” MULTIPLE SIZE=7> 9
28 <SELECT NAME=”priority” MULTIPLE SIZE=7> 9
29 <SELECT NAME=”priority” MULTIPLE SIZE=7> 9
30 <SELECT NAME=”priority” MULTIPLE SIZE=7> 9
31 <SELECT NAME=”priority” MULTIPLE SIZE=7> 8
32 <SELECT NAME=”priority” MULTIPLE SIZE=7> 9
33 <SELECT NAME=”priority” MULTIPLE SIZE=7> 8 x
34 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
35 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
36 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
37 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
38 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
39 <SELECT NAME=”priority” MULTIPLE SIZE=7> 6
40 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
41 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
42 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
43 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
44 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
45 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
46 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
47 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
48 <SELECT NAME=”priority” MULTIPLE SIZE=7> 7
Az eredmény tehát az, hogy a hibát önmagában a <SELECT> is kiváltja.