Institutionen för datavetenskap HT 1 2007/2008. Testning med JUnit



Relevanta dokument
LUNDS TEKNISKA HÖGSKOLA EDAA01 Programmeringsteknik fördjupningskurs Institutionen för datavetenskap HT 2015

Lite om felhantering och Exceptions Mer om variabler och parametrar Fält (eng array) och klassen ArrayList.

LÖSNINGSFÖRSLAG Programmeringsteknik För Ing. - Java, 5p

Föreläsning 5-6 Innehåll. Exempel på program med objekt. Exempel: kvadratobjekt. Objekt. Skapa och använda objekt Skriva egna klasser

Föreläsning 5-6 Innehåll

Chapter 4: Writing Classes/ Att skriva egna klasser.

Föreläsning 3 Innehåll. Generiska klasser. Icke-generisk lista ArrayList, skiss av implementering. Icke-generisk lista Risk för fel

Länkade listor och automatisk testning

Kort om klasser och objekt En introduktion till GUI-programmering i Java

Arv: Fordonsexempel. Arv. Arv: fordonsexempel (forts) Arv: Ett exempel. En klassdefinition class A extends B {... }

TENTAMEN PROGRAMMERINGSMETODIK MOMENT 2 - JAVA, 4P

1 Uppgift 1. a) Skapar ett Company-objekt med hjälp av den överlagrade konstruktorn. Du kan själv välja värden på instansvariablerna.

Testning av program. Verklig modell för programutveckling

Idag. Exempel, version 2. Exempel, version 3. Ett lite större exempel

TENTAMEN: Objektorienterad programmering. Läs detta! Skriv din tentamenskod på varje blad (så att vi inte slarvar bort dem).

Att skriva till och läsa från terminalfönstret

Objektsamlingar i Java

Tentamen för TDA540 Objektorienterad Programmering. Institutionen för Datavetenskap CTH HT-16, TDA540. Dag: , Tid:

2D1311 Programmeringsteknik för Bio1 och Bio2, vt 2003 Fiktivt prov På flervalsfrågorna är endast ett svar rätt om inget annat anges i frågan! Det rik

Versionshantering. Jan Erik Moström

JUnit. Junit Unit Testing. JUnit 3. JUnit 3 forts. Villkorskontroller i test. Exempel JUnit3

Dagens program. Programmeringsteknik och Matlab. Objektorienterad programmering. Vad är vitsen med att ha både metoder och data i objekten?

Classes och Interfaces, Objects och References, Initialization

Föreläsning 13 Innehåll

Objektorienterad programmering D2

Ett problem. Kontrollstrukturer och arrayer. Arrayer. Lösningen. Arrayer och hakparanteser. Exempel int[] results; results = new int[10]; // 0..

Det finns en referensbok (Java) hos vakten som du får gå fram och läsa men inte ta tillbaka till bänken.

DI-institutionen Sid 1 av 6 Hans-Edy Mårtensson Sten Sundin

Bankkonto - övning. Övning 2 Skriv en metod, geträntan, som returnerar räntan.

PROGRAMMERINGSTEKNIK TIN212

TENTAMEN. Kurs: Objektorienterad programmeringsmetodik 5DV133 Ansvarig lärare: Anders Broberg. VT-13 Datum: Tid: kl

Idag. Javas datatyper, arrayer, referenssemantik. Arv, polymorfi, typregler, typkonvertering. Tänker inte säga nåt om det som är likadant som i C.

Java: kort introduktion. Trådar. Något om mutex, Dekkers algoritm och monitorer. Javas ("inbyggda monitor") synchronized.

Grundkurs i programmering, 6 hp (725G61) Dugga 2 tillfälle 2

public och private Obs: private inte skyddar mot access från andra objekt i samma klass.

Exempel. Arrayer. Lösningen. Ett problem. Arrayer och hakparanteser. Arrayer

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Det finns en referensbok (Java) hos tentavakten som du får gå fram och läsa men inte ta tillbaka till bänken.

Föreläsning 2 Objektorienterad programmering DD1332. Typomvandling

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Idag. statiska metoder och variabler. private/public/protected. final, abstrakta klasser, gränssnitt, delegering. wrapper classes

FÖRSLAG TILL LÖSNINGAR FÖR TENTAMEN I INTERNETPROGRAMMERING MED JAVA, 5p för SY , kl

Föreläsnings 9 - Exceptions, I/O

Programmering med Java. Grunderna. Programspråket Java. Programmering med Java. Källkodsexempel. Java API-exempel In- och utmatning.

EDAA20 Föreläsning Klassen ArrayList. Viktiga operationer på ArrayList. Generisk klass

Objektorienterad programmering i Java Undantag Sven-Olof Nyström Uppsala Universitet Skansholm: Kapitel 11

Objektorienterad Programkonstruktion. Föreläsning 2 2 nov 2016

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 4 Erik Nilsson, Institutionen för Datavetenskap, LiU

Objektorienterad programmering i Java

Subklasser och arv Inledning till grafik (JFrame och JPanel). Något om interface. Objektorienterad programvaruutveckling GU (DIT011) Subklasser

Uppgiften är att beskriva en kvadrat i ett Java program. En första version av programmet skulle kunna se ut så här:

JUnit 4 - användning. Grunderna. org.junit. org.junit.test. Henrik Bergström DSV SU/KTH. Innehåller bland annat:

Arrayer. results

Att deklarera och att använda variabler. Föreläsning 10. Synlighetsregler (2) Synlighetsregler (1)

Objektorienterad programmering i Java Undantag Sven-Olof Nyström Uppsala Universitet Skansholm: Kapitel 11

DIAGNOSTISKT PROV. Tid. Hjälpmedel. Antaganden. Rättning. Övrigt. Diagnostiskt Prov. Klockan Inga

Konstruktion av klasser med klasser

Design av en klass BankAccount som representerar ett bankkonto

UML. Klassdiagr. Abstraktion. Relationer. Överskugg. Överlagr. Aktivitetsdiagram Typomv. Typomv. Klassdiagr. Abstraktion. Relationer.

KARLSTADS UNIVERSITET 12/8/09 informatik & datavetenskap Johan Öfverberg, Kerstin Andersson Laboration 4, ISG A04 och DVG A08 HT-09

DAT043 Objektorienterad Programmering

Klasshierarkier. Klasser kan byggas på redan definierade klasser

Det finns en referensbok (Java) hos vakten som du får gå fram och läsa men inte ta tillbaka till bänken.

Föreläsning 4 Innehåll. Abstrakta datatypen lista. Implementering av listor. Abstrakt datatypen lista. Abstrakt datatyp

Lösningsförslag till tentamen i EDA011, lördagen den 16 december 2006

Laboration 3, uppgift En klass för en räknare

Föreläsning 4. Klass. Klassdeklaration. Klasser Och Objekt

TENTAMEN OOP

EDAA20 Programmering och databaser. Mål komprimerat se kursplanen för detaljer. Checklista. Föreläsning 1-2 Innehåll. Programmering.

TDA550 Objektorienterad programvaruutveckling IT, forts. kurs Övning vecka 2

Föreläsning 8 - del 2: Objektorienterad programmering - avancerat

F8 - Arv. ID1004 Objektorienterad programmering Fredrik Kilander

Tentamen Programmeringsteknik II och NV2 (alla varianter) Skriv bara på framsidan av varje papper.

Övningsuppgift. Bankkonton. Steg 2. Författare: Mats Loock Kurs: Inledande programmering med C# Kurskod:1DV402

Arv. Fundamental objekt-orienterad teknik. arv i Java modifieraren protected Lägga till och modifiera metoder med hjälp av arv Klass hierarkier

Högskolan Dalarna sid 1 av 7 DI-institutionen Hans-Edy Mårtensson Sten Sundin

Identitet och ekvivalens

Testning och felhantering

Repetition av OOP- och Javabegrepp

TDDE10 m.fl. Objektorienterad programmering i Java Föreläsning 6 Erik Nilsson, Institutionen för Datavetenskap, LiU

Föreläsning 3-4 Innehåll

Inkapsling tumregler. Åtkomstmodifikatorer, instantiering, referenser, identitet och ekvivalens, samt klassvariabler. public och private

Laboration 2. returnerar true om det är omöjligt för roboten att göra move() utan att. exekveringsfel erhålls, annars returnera false.

Klasser i Java kan ha metoder och egenskaper. Metoder beskriver funktioner som klassen kan utföra. Egenskaper beskriver innehållet i klassen.

Tentamen Programmeringsteknik II Skrivtid: Hjälpmedel: Java-bok (vilken som helst) Skriv läsligt! Använd inte rödpenna!

Tentamen, EDA501/EDAA20 Programmering M MD W BK L

Repetition av OOP- och Javabegrepp

Dagens föreläsning. Arrayer och klasser. Medan ni väntar: Gå till m.voto.se/prog11 och svara på några gamla tentamensfrågor! (26 januari 2018 F3 1 )

Generisk klass med typparameter Inre klass - ListIterator

Tentamen i Programmeringsteknik I

Föreläsning 3: Abstrakta datastrukturer, kö, stack, lista

Föreläsning 2. Täcker material från lektion 1, 2, 3 och 4:

Objektorienterad programmering

Föreläsning Innehåll. Hantera många element. Exempel: polygon Godtyckligt antal element. Exempel: polygon forts

Grundläggande programmering med C# 7,5 högskolepoäng

Variabler som hör till enskilda objekt. Deklareras på översta nivån i klassen och i regel som private.

ID1004 Laboration 4, November 2012

Det finns en referensbok (Java) hos tentavakten som du får gå fram och läsa men inte ta tillbaka till bänken.

OBJEKTORIENTERAD PROGRAMVARUUTVECKLING

TENTAMEN I PROGRAMMERING. På tentamen ges graderade betyg:. 3:a 24 poäng, 4:a 36 poäng och 5:a 48 poäng

Transkript:

LUNDS TEKNISKA HÖGSKOLA EDA690 Algoritmer och datastrukturer Institutionen för datavetenskap HT 1 2007/2008 Enhetstestning Testning med JUnit När man implementerat en klass måste man, innan den kan användas, testa att den uppfyller sin specifikation. Denna typ av testning brukar kallas enhetstestning. Vid s.k. black-box testning ser man en klass som en svart låda d.v.s. man vet ingenting om hur metoderna är implementerade. Det som testas är att metoderna ger det förväntade resultatet enligt sin specifikation. Antag t ex att vi har implementerat en klass som representerar ett bankkonto med följande specifikation: class BankAccount { /** Create new account with balance 0 */ public BankAccount(); /** Get balance of account */ public int getbalance(); /** Deposit amount n on account.*/ public void deposit(int n); /** Withdraw amount n from account. If overdraft, runtime exception IllegalArgumentException is raised and balance is left unchanged */ public void withdraw(int n); För att testa att en klass uppfyller sin specifikation måste man skriva programkod som anropar metoderna i olika situationer och kontrollera att resultatet blir det förväntade. Det är viktigt att man noga tänker igenom vilka olika fall som måste testas. För klassen BankAccount finns t ex följande fall som bör kontrolleras: getbalance() skall ge resultatet 0 för ett nyskapat konto deposit(n) följt av getbalance() skall ge resultatet n deposit(t1); withdraw(t2); ; deposit(tn); (med legala parametervärden för uttag) följt av getbalance() skall ge resulatet t1-t2+tn withdraw(n) ; där n>getbalance() kall generera IllegalArgumentException. Det är viktigt att testfallen också omfattar onormala fall eller gränsfall. För bankkontoklassen är ett sådant fall att man försöker ta ut mer pengar än vad som finns. Enligt specifikationen skall då IllegalArgumentException genereras. För en klass som hanterar listor kan intressanta gränsfall att kontrollera vara att ta bort det enda elementet i en lista eller att sätta in ett element allra först eller sist i listan. Enhetstestning med JUnit Ett sätt att genomföra testning enligt ovan är att skriva en main-metod i den klass som skall testas och låta den innehålla de kombinationer av metodanrop som motsvarar de olika testfallen. För att förenkla testförfarandet speciellt när många klasser skall enhetstestas kan man ha hjälp av ett verktyg. Vi skall här beskriva ett sådant verktyg, JUnit. I JUnit kan man samla alla test som rör en viss klass i en testklass, eventuellt samla ihop alla test i flera sådana testklasser till en testsvit, utföra alla tester och få en grafisk presentation av resultatet. Till varje klass som skall testas med hjälp av JUnit skriver man en motsvarande testklass som kan se ut så här: import junit.framework.test;

import junit.framework.testcase; import junit.framework.testsuite; public class TestMyClass extends TestCase { public TestMyClass(String name) { super(name); protected void setup() { protected void teardown() { public void testxxx() { public void testyyy() { public static void main(string[] args) { junit.swingui.testrunner.run(testmyclass.class); Konstruktorn skall alltid anropa superklassens konstruktor med sin egen parameter name som parameter. Det är ramverket JUnit som sedan kommer att anropa denna konstruktor vid test. Metoderna setup och teardown anropas av ramverket före, respektive efter varje test i testklassen. I setup kan man därför initiera det tillstånd man vill utgå ifrån i varje testfall, t ex skapa en instans av den klass som skall testas. I teardown kan man städa upp efter varje test t ex genom att frigöra resurser som man allokerat i setup. I main-metoden skapas en TestRunner som utför testen och presenterar resultaten via ett grafiskt användargränssnitt. Lägg märke till att parametern till run i main-metoden skall vara en referens till klassen som skall testas. Varje metod som har prefixet test kommer att utföras av ramverket. Metoderna testxxx, testyyy, i exemplet ovan skall alltså innehålla de sekvenser av metodanrop som motsvarar testfall man vill genomföra. Observera att testmetoderna måste vara publika för att ramverket skall kunna anropa dem. För att informera testramverket om utfallet finns ett antal metoder i klassen TestCase.Dessa kan alltså användas i de subklasser där testmetoderna finns såsom TestMyClass ovan. (En utförligare förteckning över metoderna, med kommentarer finns i Appendix). asserttrue(string message, boolean condition) assertequals(string message, TYPE expected, TYPE actual); assertnotnull(string message, Object obj); assertnull(string message, Object obj); assertsame(string message, Object expected, Object actual); fail(string message); Assert betyder ungefär att hävda, påstå. I metoderna ovan är message det meddelande som används för att generera felmeddelande i det grafiska gränssnittet vid körning av testfallet om utfallet inte är det förväntade. TYPE är någon av typerna boolean, byte, int, short, long, float, double eller Object. Om påståendena inte är sanna så genererar ramverket meddelanden om att testfallet inte gav förväntat resultat. failmetoden används när man utan att behöva kontrollera någonting vet att man misslyckats. Den kan t ex användas i samband med att det förväntade utfallet är att exception genereras (se exemplet med test av BankAccount nedan). Exempel på testklass i JUnit

Låt oss som exempel ta test av bankkontoklassen. Följande klass innehåller testmetoder motsvarande det första, andra och det sista av de tester som räknats upp tidigare: import junit.framework.test; import junit.framework.testcase; import junit.framework.testsuite; public class TestBankAccount extends TestCase { private BankAccount theaccount; // the account used for tests below public TestBankAccount(String name) { super(name); /** Let theaccount reference a new account before each test */ protected void setup() { theaccount = new BankAccount(); /** Clear the Account after each test */ protected void teardown() { theaccount = null; /** Test that balance of a newly created account is 0 */ public void testnewaccount() { assertequals("new account, balance not 0", 0, theaccount.getbalance()); /** Test that a single deposit gives correct balance */ public void testdeposit() { theaccount.deposit(100); assertequals("wrong balance after deposit", 100, theaccount.getbalance()); /** Test that illegal withdrawal raises IllegalArgumentException */ public void testoverdraft() { theaccount.deposit(100); try { theaccount.withdraw(200); fail("should raise IllegalArgumentException"); catch(illegalargumentexception e) { // successful test public static void main(string[] args) { junit.swingui.testrunner.run(testbankaccount.class); I testklassen deklareras ett attribut theaccount som är det konto som testas. I metoden setup skapas före varje test ett nytt konto som theaccount refererar till. I teardown tas det bort (egentligen onödigt här eftersom setup ändå skapar ett nytt före nästa test). Den första testen testnewaccount kontrollerar att ett nytt konto har behållningen 0. Om så inte är fallet kommer ett meddelande New account. att visas av ramverket. Metoden testdeposit kontrollerar att behållningen är korrekt efter en enda insättning. Lägg märke till hur den sista testen testoverdraft testar om det verkligen genereras IllegalArgumentException vid försök till att ta ut för mycket pengar. Om satsen theaccount.withdraw(200) inte genererar en exception kommer exekveringen att fortsätta i try-blocket. Detta motsvarar misslyckat test och vi kan därför använda fail-satsen för att informera ramverket. Om vi däremot får en exception hamnar vi i catch-grenen vilket motsvarar ett lyckat test och inget felmeddelande skall i detta fall genereras. För att köra testen kompilerar man klassen som skall testas, testklassen och kör sedan testklassen med det vanliga kommandot, i detta fall java TestBankAccount. main-metoden i TestBankAccount kör igång ramverket som sedan utför alla testfallen. Resultatet presenteras grafiskt Så länge testfallen är lyckade visas grönt ljus i den grafiska presentationen av resultatet. Så snart ett test går fel (enligt assert-sats) blir det rött ljus och ett meddelande genererat från parametrarna i assert-satsen visas.

JUnit rapporterar alltså vilket/vilka testfall som eventuellt gick fel. Härav kan man oftast dra slutsatser om vilken/vilka metoder det är i den testade klassen som är felaktiga. Skulle t ex testfallet testnewaccount ovan ge felmeddelande så måste något vara fel med antingen konstruktorn i BankAccount eller med metoden get- Balance. Man får i så fall försöka korrigera och kompilera om samt köra testerna på nytt tills man känner sig nöjd med funktionaliteten i klassen. Eventuellt kommer man under denna process på ytterligare test som bör utföras. I så fall får man komplettera testklassen med fler testmetoder, kompilera om och köra. Observera att när man väl kört igång ramverket en gång behöver man inte avsluta det så länge man vill fortsätta att testa. Det kan köras i bakgrunden genom att (i detta fall) ge kommandot java TestBankAccount & I det grafiska gränssnittet finns möjlighet (knappen märkt Run) att starta om hela testet på nytt. Prova JUnit I filerna /usr/local/cs/algodat/banktest/bankaccount.java /usr/local/cs/algodat/banktest/testbankaccount.java finns färdig implementation av bankkontoklassen och dess testklass. Kopiera dem till din egen katalog och kompilera dem. Glöm inte att först utföra kommandot initcs. Kör därefter igång JUnit genom att utföra kommandot java TestBankAccount & Alla tester går igenom. Se fig. 1. Verktyget rapporterar att 4 Runs genomförts (det finns fyra testmetoder i klassen TestbankAccount) samt att antalet Failures och Errors är 0. Dessutom visas grönt ljus. Verktyget skiljer mellan två sorters fel; Failures och Errors. Failures är den typ av fel som upptäcks genom assertsatserna. Errors är oförutsedda fel som kan bero på att man skrivit kod som leder till exekveringsfel i klassen som testas eller i testmetoderna, t ex råkar ut för att få ArrayIndexOutOfBoundsException eller dylikt. För att få se hur det blir när test går fel kan du introducera något fel i klassen BankAccount. Låt t ex tillgången på ett nyskapat konto bli 100 genom att ändra i konstruktorn. Kompilera sedan om BankAccount och kör testerna igen genom att klicka på Run-knappen i JUnit-fönstret Fig 1: Testklassen TestBankAccount med 4 testfall har körts. Inga fel rapporteras.

Nu rapporteras inte mindre än 4 failures. Se fig. 2. Alla fyra testen ger fel resultat. I den övre av de båda större textrutorna i fönstret räknas namnen på de testmetoder som gick fel upp. Den första är markerad och i den undre textrutan finns det genererade felmeddelandet för den markerade metoden. Du kan markera någon av de andra testmetoderna i den övre textrutan och får då fram felutskrifter för denna metod i den undre. Eftersom det första testet är det allra enklaste och detta gick fel verkar det logiskt att försöka åtgärda detta först. (I detta fall är det ju faktiskt så att alla de andra felen är följdfel av att konstruktorn är felaktig). Korrigera konstruktorn, kompilera och kör testen, som nu ger grönt ljus igen. Introducera nu i stället ett fel i metoden withdraw. Kommentera helt enkelt bort den inledande if-satsen så att metoden aldrig genererar IllegalArgumentException. Kompilera BankAccount och kör testerna på nytt. Nu blir det bara ett failure. Det kommer från den sista testmetoden och meddelandet är att det borde blivit en exception. Fig 2: Testklassen TestBankAccount med 4 testfall har körts. Fyra fel (failures) rapporteras i den övre av de båda större textrutorna. Det första test som gick fel är markerat (testnewaccount). Ett meddelande som genererats från assert-satsen i testnewaccount visas i den undre textrutan.

Test av flera klasser med JUnit För att kunna utföra tester av flera klasser på en gång kan tester sammanföras till en s.k. testsvit. Ett klasskelett för en testsvit för klasserna TestMyClass1, TestMyClass2, visas nedan. import junit.framework.test; import junit.framework.testcase; import junit.framework.testsuite; public class TestAll extends TestCase { public TestAll(String name) { super(name); public static Test suite() { TestSuite thesuite = new TestSuite(); // Add all tests in TestMyClass1 thesuite.addtestsuite(testmyclass1.class); // Add all tests in TestMyClass2 thesuite.addtestsuite(testmyclass2.class);. return thesuite; public static void main(string[] args) { junit.swingui.testrunner.run(testall.class); Ytterligare test i sviten läggs till med metoden addtestsuite(..) för samtliga testklasser som skall ingå i sviten. TestAll kompileras och körs med kommandot java TestAll. Därvid kommer alla testmetoder som finns i de klasser som ingår i testsviten att köras. Mera information om JUnit Testramverket JUnit är skrivet av Erich Gamma och Kent Beck och är en s.k. Open Source Software. Mer information finns på adressen http://www.junit.org/. På huvudsidan finns (i skrivande stund) en länk Getting Started. Under denna finns ett dokument som i sin tur innehåller länkar till artiklar om hur man kan använda JUnit och till dokumentation. Från huvudsidan kan man också ladda ner den senaste versionen av produkten. Det kommer ganska ofta nya versioner så bli inte förvånad om den version du själv laddar hem är lite annorlunda än den som vi installerat på skolan. Version 3.8 är installerad på skolans datorer. Dess dokumentation finns på adressen http://www.junit.org/junit/ javadoc/3.8/index.htm. Se t ex klassen Assert för en fullständig förteckning över alla assert-metoder.

Appendix /** Assert that a condition is true */ public void asserttrue(string message, boolean condition); /** Assert that an object isn t null */ public void assertnotnull(object object); /** Assert that an object is null */ public void assertnull(object object); /** Assert that two objects are equal */ public void assertequals(string message, Object expected, Object actual); /** Assert that expected and actual refer to the same object */ public void assertsame(string message, Object expected, Object actual); /** Assert that expected and actual don t refer to the same object */ public void assertnotsame(string message, Object expected, Object actual); /** Assert that two Strings are equal */ public void assertequals(string message, String expected, String actual); /** Assert that two booleans are equal */ public void assertequals(string message, boolean expected, boolean actual); /** Assert that two bytes are equal */ public void assertequals(string message, byte expected, byte actual); /** Assert that two chars are equal */ public void assertequals(string message, char expected, char actual); /** Assert that two shorts are equal */ public void assertequals(string message, short expected, short actual); /** Assert that two ints are equal */ public void assertequals(string message, int expected, int actual); /** Assert that two longs are equal */ public void assertequals(string message, long expected, long actual); /** Assert that two doubles are equal concerning a delta. If the expected value is infinity then the delta is ignored. */ public void assertequals(string message, double expected, double actual, double delta); /** Assert that two floats are equal concerning a delta. If the expected value is infinity then the delta is ignored. */ public void assertequals(string message, float expected, float actual, float delta); /** Report failure with the given message */ public void fail(string message); Observera att förteckningen ovan inte är fullständig. För fullständig information om vilka metoder som finns i klassen Assert i JUnit se http://www.junit.org/junit/javadoc/3.8/index.htm. Notera också att metoder som i sitt namn inehåller Equals gör jämförelser mellan expected och actual med metoden equals. I metoder vars namn innehåller Same däremot anses expected och actual vara samma endast om operationen == mellan objekten ger resultatet true.