Är testfallen tillräckliga? (Junit)
Uppgift:
Nedanstående testsvit kontrollerar metoden checkArgument i klassen C. Vilket av
påståendena är sant?
public static boolean checkArgument(String arg) {
return arg.trim().length() > 0;
}
@Test
public void test1() {
assertTrue(C.checkArgument("abc"));
}
@Test
public void test2() {
assertTrue(C.checkArgument(" abc"));
}
@Test
public void test3() {
assertTrue(C.checkArgument("abc "));
}
@Test
public void test4() {
assertTrue(C.checkArgument(" abc "));
}
@Test
public void test5() {
assertFalse(C.checkArgument(""));
}
@Test
public void test6() {
assertFalse(C.checkArgument(" "));
a. Metoden klarar inte alla testen.
b. Det saknas ett viktigt testfall ovan.
c. Testfallen är tillräckliga
(Uppgiften är från en gammal tenta i objektorienterad programmering och eftersom svar saknas på denna uppgift så vänder jag mig till er i förhoppning att kanske få svar på mina tankar)
Min tankegång:
Så dessa tester kommer antingen att testa om returvärdet blir true (assertTrue) om sträng-argumentet är större än noll. Annars testas ifall metoden returnerar false (assertFalse). Metoden trim() används för att ta bort eventuella mellanrum (leading and trailing spaces) före och/eller innan själva ordet. Exempelvis om argumentet är “abc “ (längd 4) så kommer trim() ta bort mellanrummet efter 'c' så att vi får “abc” (längd 3).
Jag ser inga felaktiga test och har kört alla tester (alla 6 tester är gröna).
Nu är frågan om det saknas ett viktigt testfall (b) eller om testfallen faktiskt är tillräckliga (c). Min första tanke är att det saknas ett test som testar ifall argumentet är null. Om strängen är null så kommer väl ett NullPointerException kastas, och därför så tycker jag påstående b låter mest rimligt? Frågan är om ett null-test räknas som ett viktigt testfall i detta sammanhang och om det saknas ytterligare testfall som bör läggas till?
Du resonerar helt rätt - null-test är ett mycket viktigt testfall i detta och de flesta andra sammanhang. Du kan enkelt verifiera detta genom att lägga till ett sjunde testfall som testar null som argument.
Lindehaven skrev:Du resonerar helt rätt - null-test är ett mycket viktigt testfall i detta och de flesta andra sammanhang. Du kan enkelt verifiera detta genom att lägga till ett sjunde testfall som testar null som argument.
Okej, jag har lagt till ytterligare ett testfall (test7) nu, men när jag kör testet så får jag felmeddelandet "test failed". Gör jag något fel? (se nedan)
@Test
public void test7() {
String str = null;
assertNull(SomeClass.checkArgument(str));
}
Problemet är att själva koden inte klarar ett null-test. Du måste ju lägga till en koll så att arg != null.
Själv tycker jag uppgiften är något oklar. Ett null-test saknas uppenbarligen, men det är ju inte bara ett test som ska läggas till, utan koden måste ju också ändras, och alltså är det ju inte bara ett testfall som saknas..
Håller med AlvinB. Prova att rätta koden med try och catch så att alla testfall går igenom.
Jag har provat att göra om metoden, men lyckas inte. Problemet är väl att den har returtyp boolean, och testet (assertNull) undersöker väl om returtypen är null? Bör man byta returtyp på metoden (checkArgument) från boolean till int där 3 siffror används för att motsvara antingen true, false eller null?
Testet borde ju vara något sådant:
assertFalse(C.checkArgument(null));
Metoden bör ju kolla ifall argumentet är null och i så fall returnera false eftersom det inte är ett giltigt argument. Det är inte nödvändigt att ge någon mer information eftersom det inte spelar någon roll ifall det är en tom sträng eller null som gör att argumentet blir fel. Det viktiga är att man vet att argumentet inte funkar.
Dock kommer du märka att koden kommer att ge ifrån sig en NullPointerException ifall argumentet är null, vilket du måste åtgärda. Hur tror du att man gör det? (Try-catch är fel svar)
Håller med AlvinB - låt metoden returnera false om argumentet är null. Jag hävdar dock att try-catch är en av de kodkonstruktioner som enkelt kan lösa detta. Det finns fler lösningar (som vanligt är i programmering).
Fast där har du nog fel, tyvärr. NullPointerException är en RuntimeException, och sådana ska man inte använda try-catch för, dels för att exceptions är ganska ineffektiva, men framför allt för att det finns ett mycket enkelt sätt att förhindra dem.
En enkel if-sats med arg != null är allt man behöver för att förhindra en NullPointerException. Try-catch ska endast användas för att ta hand om oförutsedda exceptions.
Nu gick null-testet igenom, men istället för att använda assertNull så använde jag assertFalse. Är det ok? (se uppdatering nedan)
checkArgument:
public static boolean checkArgument(String arg) {
if(arg != null) return arg.trim().length() > 0;
else return false;
}...
null-testet:
...
test 7:
public void test7() {
assertFalse(C.checkArgument(null));
}
Just precis. Helt rätt. Nu har du ändrat koden så att det inte blir någon NullPointerException, och du har lagt till ett testfall som säkerställer att null-argument returnerar false.
AlvinB skrev:Fast där har du nog fel, tyvärr. NullPointerException är en RuntimeException, och sådana ska man inte använda try-catch för, dels för att exceptions är ganska ineffektiva, men framför allt för att det finns ett mycket enkelt sätt att förhindra dem.
En enkel if-sats med arg != null är allt man behöver för att förhindra en NullPointerException. Try-catch ska endast användas för att ta hand om oförutsedda exceptions.
Jag menar att try-catch är ett sätt att lösa det på - inte fel men inte det bästa. En if-sats är bättre.
Lindehaven skrev:AlvinB skrev:Fast där har du nog fel, tyvärr. NullPointerException är en RuntimeException, och sådana ska man inte använda try-catch för, dels för att exceptions är ganska ineffektiva, men framför allt för att det finns ett mycket enkelt sätt att förhindra dem.
En enkel if-sats med arg != null är allt man behöver för att förhindra en NullPointerException. Try-catch ska endast användas för att ta hand om oförutsedda exceptions.
Jag menar att try-catch är ett sätt att lösa det på - inte fel men inte det bästa. En if-sats är bättre.
Ja, det beror nog på vad man menar med fel... RuntimeExceptions finns bara för att visa att någonting har gått fel, de är inte till för att fångas upp av en try-catch-sats i en normal exekvering av kod.
Vore jag examinatör skulle jag ge fel för en sådan lösning, och jag tror de flesta erfarna Java-programmerare skulle vara benägna att hålla med.
Stort tack för er hjälp. Jag är väldigt nöjd