Den här artikeln visar hur man kan använda JUnit och Eclipse för att skapa tester för sin kod. I artikeln kommer JUnit att användas tillsammans med Eclipse 3.1 och Java 1.5.
En av de största svårigheterna med att utveckla ett större program är att hitta felen i det. Man kan vara säker på att det finns fel, problemet är att hitta dem. Den vanligaste metoden för att hitta fel är testning. Att testa manuellt är tidsödande, speciellt eftersom man efter varje ändring, i allmänhet, återigen behöver testa en stor mängd funktioner som kan ha påverkats. Det finns en mängd olika sätt att testa på och det finns många olika typer av tester man kan använda sig av. Den här artikeln kommer att behandla automatisk enhetstestning. JUnit (http://www.junit.org) är ett ramverk för Java som kan används för att skriva och köra tester.
För att skapa ett nytt test behöver klassen ärva ifrån klassen TestCase. Det finns två metoder i TestCase som är viktiga och som man ofta behöver omdefiniera, nämligen setUp() och tearDown(). Metoden setUp() körs innan varje enskild testmetod körs. På liknande sätt körs tearDown() efter att varje enskild testmetod har körts. Ett exempel:
public class SimpleTest extends TestCase { private ArrayList
Genom att använda metorderna i setUp() och tearDown() garanterar man att varje enskild testmetod får rätt förutsättningar. När SimpleTest körs kommer ordningen på metodanrop alltså att vara setUp(), testSimple(), tearDown(). Alla metoder som skall utföra själva testerna skall ha prefixet test. Metoden testSimple() är ett bra exempel på hur en testmetod kan se. Notera anropet till metoden assertEquals(). Den metoden verifierar att de två argumenten, i det här fallet 1 och list.size(), är lika. Om de inte är lika så har testet misslyckats. Den här korta introduktionen räcker för att man skall kunna ge oss i kast med ett större exempel.
Genom att implementera en kö, SimpleQueue, och sedan skapa tester för dess olika operationer får man en liten inblick i hur JUnit fungerar. Kön implementeras som en länkad list med en referens till huvudet och en referens till svansen. När kön är tom refererar både huvudet och svansen till samma element. Varje element representeras av klassen QueueEntry, som innehåller själva elementet och en referens till nästa element i den länkade listan.
Bild 1.1 – Så här kan det se ut när man arbetar med Eclipse och JUnit.
Börja med att skapa ett nytt Java-projekt i Eclipse och kalla det t ex för JUnit example. Skapa ett nytt paket unittesting och skapa sedan klassen SimpleQueue. För att skapa QueueEntry så högerklicka på SimpleQueue.java (i Package Explorer) och välj New och sedan Class och klicka sedan i rutan Enclosing type. Då kommer QueueEntry att skapas som en nästlad klass i SimpleQueue. Efter att ha lagt till grundera för kön så ser skalet till kön ut så här (se även bild 1.1):
package unittesting;
/** * @param * @author André Isaksson */ public class SimpleQueue { private int size = 0; private QueueEntry head = null; private QueueEntry tail = null;
/** * */ public SimpleQueue() { head = tail = new QueueEntry(null); }
/** * * @return the size of the queue. */ public int size() { return size; }
/** * * @return true if the queue is empty, false otherwise. */ public boolean isEmpty() { return size == 0; }
/** * Represents an entry in the queue. * * @author André Isaksson * @param */ public class QueueEntry { // The data stored in this entry. private T data; // The next entry in the queue. private QueueEntry next;
/** * @return the data stored in this entry. */ public T get() { return data; }
/** * @param data The data to set. */ public void set(T data) { this.data = data; }
/** * @return The next entry in the queue. */ public QueueEntry getNext() { return next; }
/** * @param next The next to set. */ public void setNext(QueueEntry next) { this.next = next; } } }
I kön finns också några enkla metoder för att hålla koll på hur många element som finns i kön och om den är tom eller inte. Kön har en typparameter som gör det möjligt att skapa en typsäker kö. Nu är det dags att börja skriva våra tester för de metoder som finns i kön. Först skapar man ett nytt paket unittesting.tests. Högerklicka sedan på paketet i vyn Package Explorer och välj New och därefter JUnit Test Case, svara ja på frågan om du vill att junit.jar skall läggas till i sökvägen, ge den namnet TestSimpleQueue och klicka i rutan bredvid setUp(). Efter att ha lagt till en referens till kön och ha implementerat setUp() och testEmptyQueue() ser TestSimpleQueue ut så här:
/** * Test that an empty queue shows up as empty. */ public void testEmptyQueue() { assertEquals(0, queue.size()); assertEquals(true, queue.isEmpty()); } }
För att köra testet så högerklicka på TestSimpleQueue.java (i Package Explorer) och välj Run As och sedan JUnit Test och en dialogruta visas.
Bild 1.2 – Den här panelen visar alla tester och vilka som har lyckas respektive misslyckats.
Med hjälp av den kan man se vilka tester som finns och vilka som har misslyckats. För att köra alla testerna trycker man på den lilla gröna pilen i det övre högra hörnet (se bild 1.2). Eftersom testerna i det här fallet har lyckats, kan man fortsätta att lägga till metoder till kön. Börja med metoden enqueue() och de metoder som behövs för att testa den.
/** * Adds an object to the back of the queue. * * @param obj The object to add. */ public void enqueue(T obj) { if (tail.get() == null) { tail.set(obj); } else { QueueEntry newEntry = new QueueEntry(obj); tail.setNext(newEntry); tail = newEntry; }
size++; }
För att testa den behövs två metoder: testSingleEnqueue() och testMultipleEnqueue(). De ser ut så här:
/** * Test if it's possible to add one item. */ public void testSingleEnqueue() { queue.enqueue(1); assertEquals(1, queue.size()); assertEquals(false, queue.isEmpty()); }
/** * Test if it's possible to add multiple items. */ public void testMultipleEnqueue() { int items = 5;
for (int i = 0;i < items;i++) queue.enqueue(i);
// Check that all items are in the queue. assertEquals(items, queue.size()); assertEquals(false, queue.isEmpty()); }
Metoden testSingleEnqueue() kontrollerar att det går att lägga till ett objekt genom att undersöka om kön har rätt längd och inte är tom. Testet testMultipleEnqueue() är mycket likt, skillnaden är att den lägger till fem element. Nu är det dags att köra testerna igen, förhoppningsvis lyckas dem. Med en fungerande enqueue() så är det dags att implementera dequeue() som tar bort det första elementet i kön och returnerar det. Om kön är tom när kommer ett undantag att kastas.
/** * * @return the first item in the queue. */ public T dequeue() { if (isEmpty()) throw new IllegalStateException("Queue is empty");
QueueEntry temp = head; head = head.getNext(); size--;
return temp.get(); }
Det finns flera intressanta saker att testa när det gäller dequeue(). Man måste undersöka att rätt element returneras, att köns storlek minskas och att ett undantag kastas om kön är tom. Metoden för att testa om ett undantag kastas skiljer sig lite från de tidigare testmetoderna och ser ut så här:
/** * Check that the appropriate exception is thrown * when trying to dequeue an item from an empty queue. */ public void testDequeueFailure() { try { queue.dequeue(); fail("No IllegalStateException thrown!"); } catch (IllegalStateException ex) { // If we get here everything works! } }
Här försöker man att ta ett element ur den tomma kön. Om undantaget inte kastas kommer metoden fail() att köras som kör att testet misslyckas. Om däremot allt fungerar och undantaget kastas så kommer fail() aldrig att anropas. Nu återstår bara de två metoderna för att verifiera att elementen plockas bort från kön i rätt ordning. De kan skrivas så här:
/** * Check that a single dequeue works. */ public void testSingleDequeue() { queue.enqueue(1); // Check that we got the right element of and // that the queue now is empty. assertEquals(1, queue.dequeue()); assertEquals(true, queue.isEmpty()); assertEquals(0, queue.size()); }
/** * Check that multiple enqueue items comes * of the queue in right order (FirstInFirstOut). */ public void testMultipleDequeue() { int items = 5;
// Enqueue a few items for (int i = 0;i < items;i++) queue.enqueue(i);
// Now, let's dequeue them and check that // they are in the right order. for (int i = 0;i < items;i++) assertEquals(i, queue.dequeue());
// Check that the queue really is empty. assertEquals(true, queue.isEmpty()); assertEquals(0, queue.size()); }
Dessa metoder är mycket lika de som används för att testa enqueue() och är relativt självförklarande. Nu är det dags att återigen köra alla tester och se så att kön fungerar. Förhoppningsvis går alla tester igenom och kön är då färdig att börja användas.
Den här korta genomgången har visat hur man kan använda JUnit och Eclipse för att skriva automatiska tester. Det finns mycket mer att säga om JUnit, men framförallt om testning i allmänhet. JUnit har också portats till .NET och kallas då för NUnit. Är man intresserad av testning kan jag rekommendera Sara Ford’s weblog som handlar om generell testning men också om hur Microsoft testar Visual Studio.
0 Kommentarer