Mittwoch, 8. Oktober 2014

 

Musterlösung zu Unit-Tests

Musterlösung zur Aufgabe zu Unit-Tests

Folgende Grenzfälle werden getestet:
Sonderfälle:
"Normalfälle":
Weitere Annahmen, die aus der Angabe nicht unbedingt hervorgehen:
Die Artikel (Elemente/Items) werden in der Reihenfolge und der gegebenen Anzahl gespeichert, als addItems() aufgerufen wurde. Wird ein Element mit der Anzahl 5 in den Warenkorb aufgenommen, so wird das Element 5 mal gespeichert.

Testklasse:
Die Kommentare wurden für diesen Beitrag weggelassen, da die Klasse ohnedies schon sehr lange ist.
import java.util.Iterator;
import junit.framework.TestCase;

public class ShoppingCartTest extends TestCase {

    private ShoppingCart cart;
    private ItemCount itemCount;

    private Item[] items = { new Item(1), new Item(2), new Item(3) };

    protected void setUp() throws Exception {
        cart = new MyCart();
        itemCount = (ItemCount) cart;
    }

    protected void tearDown() throws Exception {
    }

    public void testAddItems0() {
        try {
            cart.addItems(items[0], 0);
            assertEquals("testDeleteItems0: 0 Elemente", 0, cart.itemCount());
        } catch (NegativeCountException e) {
            fail("testAddItem0: es dürfte keine NegativeCountException"
                 + " geworfen werden");
        }
    }

    public void testAddItemNegativ() {
        try {
            cart.addItems(items[0], -23);
            fail("testAddItemNegativ: es müsste eine NegativeCountException"
                 + " geworfen werden");
        } catch (NegativeCountException e) {
        }
    }

    public void testDeleteItems0() {
        try {
            cart.addItems(items[0], 1);
            cart.deleteItems(items[0], 0);
            assertEquals("testDeleteItems0: 1 Element", 1, cart.itemCount());
        } catch (NegativeCountException e) {
            fail("testDeleteItems0: es dürfte keine NegativeCountException"
                 + " geworfen werden");
        } catch (NoSuchItemException e) {
            fail("testDeleteItems0: es dürfte keine NoSuchItemException"
                 + " geworfen werden");
        }
    }

    public void testDeleteItemsNoSuchItem() {
        try {
            cart.addItems(items[0], 1);
            cart.deleteItems(items[1], 1);
            fail("testDeleteItemsNoSuchItem: es müsste NoSuchItemException"
                 + " geworfen werden");
        } catch (NegativeCountException e) {
            fail("testDeleteItemsNoSuchItem: es dürfte keine" 
                 + " NegativeCountException geworfen werden");
        } catch (NoSuchItemException e) {
            assertEquals("testDeleteItemsNoSuchItem: 1 Element", 1,
                    cart.itemCount());
        }
    }

    public void testDeleteItemNegativ() {
        try {
            cart.addItems(items[0], 2);
            cart.deleteItems(items[0], -23);
            fail("testAddItemNegativ: es müsste eine NegativeCountException"
                 + " geworfen werden");
        } catch (NegativeCountException e) {
        } catch (NoSuchItemException e) {
            fail("testAddItemNegativ: es dürfte keine NoSuchItemException"
                 + " geworfen werden");
  }
    }

    public void testAddItems10() {
        try {
            cart.addItems(items[0], 3);
            cart.addItems(items[1], 3);
            cart.addItems(items[2], 4);
            assertEquals("testAddItems10: 10 Elemente", 10, cart.itemCount());
        } catch (NegativeCountException e) {
            fail("testAddItems10: es dürfte keine NegativeCountException"
                 + " geworfen werden");
        }
    }

    public void testAddDeleteItems5() {
        try {
            cart.addItems(items[0], 3);
            cart.addItems(items[1], 3);
            cart.addItems(items[2], 4);
            cart.deleteItems(items[0], 2);
            cart.deleteItems(items[2], 2);
            cart.deleteItems(items[1], 1);
            assertEquals("testAddDeleteItems5: 5 Elemente", 5, cart.itemCount());
        } catch (NegativeCountException e) {
            fail("testAddDeleteItems5: es dürfte keine NegativeCountException"
                 + " geworfen werden");
        } catch (NoSuchItemException e) {
            fail("testAddDeleteItems5: es dürfte keine NoSuchItemException"
                 + " geworfen werden");
        }
    }

    public void testIterator() {
        try {
            cart.addItems(items[0], 3);
            cart.addItems(items[1], 3);
            cart.addItems(items[2], 4);
            Iterator<Item> iterator = cart.iterator();
            int cntItems = 0;
            Item[] stroredItems = new Item[10];
            while (iterator.hasNext()) {
                stroredItems[cntItems] = iterator.next();
                cntItems++;
            }
            assertEquals("testIterator: 10 Elemente", 10, cntItems);
            for (int i = 0; i < 3; i++) {
                assertEquals("testIterator: Element sollte gleich sein",
                        items[0], stroredItems[i]);
                System.out.println(stroredItems[i]);
            }
            for (int i = 3; i < 6; i++) {
                assertEquals("testIterator: Element sollte gleich sein",
                        items[1], stroredItems[i]);
                System.out.println(stroredItems[i]);
            }
            for (int i = 6; i < 10; i++) {
                assertEquals("testIterator: Element sollte gleich sein",
                        items[2], stroredItems[i]);
                System.out.println(stroredItems[i]);
            }
        } catch (NegativeCountException e) {
            fail("testIterator: es dürfte keine NegativeCountException"
                 + " geworfen werden");
        }
    }

    public void testItemCount() {
        try {
            cart.addItems(items[0], 3);
            cart.addItems(items[1], 3);
            cart.addItems(items[0], 1);
            cart.addItems(items[2], 4);
            cart.addItems(items[0], 2);
            assertEquals("testItemCount: Anzahl falsch", 6,
                    itemCount.itemCount(items[0]));
            assertEquals("testItemCount: Anzahl falsch", 3,
                    itemCount.itemCount(items[1]));
            assertEquals("testItemCount: Anzahl falsch", 4,
                    itemCount.itemCount(items[2]));
        } catch (NegativeCountException e) {
            fail("testItemCount: es dürfte keine NegativeCountException"
                 + " geworfen werden");
        } catch (NoSuchItemException e) {
            fail("testItemCount: es dürfte keine NoSuchItemException"
                 + " geworfen werden");
        }
    }

    public void testItemCountNosuchItem() {
        @SuppressWarnings("unused")
        int cnt;
        try {
            cnt = itemCount.itemCount(items[0]);
            fail("testItemCountNosuchItem: es müsste eine NoSuchItemException"
                 + " geworfen werden");
        } catch (NoSuchItemException e) {
        }
        try {
            cart.addItems(items[1], 3);
            cnt = itemCount.itemCount(items[0]);
            fail("testItemCountNosuchItem: es müsste eine NoSuchItemException"
                 + " geworfen werden");
        } catch (NegativeCountException e) {
            fail("testItemCountNosuchItem: es dürfte keine"
                 + " NegativeCountException geworfen werden");
        } catch (NoSuchItemException e) {
        }
    }
}

Implementierung des Interfaces ShoppingCart:
Zusätzlich zur originalen Aufgabenstellung wurde noch folgendes Interface implementiert, damit man einfach die Anzahl eines bestimmten Items bestimmen kann:
public interface ItemCount {
    public int itemCount(Item anItem) throws NoSuchItemException;
}

Zur Speicherung der Items wird einfach eine ArrayList verwendet.
import java.util.ArrayList;
import java.util.Iterator;

public class MyCart implements ShoppingCart, ItemCount {

    private ArrayList<Item> items = new ArrayList<Item>();

    public void addItems(Item anItem, int quantity)
            throws NegativeCountException {
        if (quantity < 0) {
            throw new NegativeCountException();
        }
        for (int i = 0; i < quantity; i++) {
            items.add(anItem);
        }
    }

    public void deleteItems(Item anItem, int quantity)
            throws NegativeCountException, NoSuchItemException {
        if (quantity < 0) {
            throw new NegativeCountException();
        }
        for (int i = 0; i < quantity; i++) {
            if (!items.remove(anItem))
                throw new NoSuchItemException();
        }
    }

    public int itemCount() {
        return items.size();
    }

    public Iterator<Item> iterator() {
        return items.iterator();
    }

    @Override
    public int itemCount(Item anItem) throws NoSuchItemException {
        int cnt = 0;
        if (!items.contains(anItem)) {
            throw new NoSuchItemException();
        }
        for (Item item : items) {
            if (item == anItem) {
                cnt++;
            }
        }
        return cnt;
    }

}
Weiters müssen natürlich die geforderten Exceptions implementiert werden (Kommentare wurden auch hier weggelassen):
public class NegativeCountException extends Exception {
}
public class NoSuchItemException extends Exception {
}

Die Klasse für die Artikel (Item) wurde einfach durch eine Nummer ergänzt, die beim Konstruktor angegeben werden muss. Für eine realistische Anwendung müsste diese Klasse noch erweitert werden:
public class Item {
  private int itemNr = 0;

  public Item(int itemNr) {
    this.itemNr = itemNr;
  }

  @Override
  public String toString() {
    return "Item " + itemNr;
  }
}

Labels: , , ,


Montag, 10. März 2014

 

Aufgabe zu Unit-Tests (POS1: 2BHIF)

In einem Online-Shop wird unter anderem ein Warenkorb benötigt. Schreiben Sie Unit-Tests zu folgendem Interface (welches Sie natürlich auch implementieren müssen):

import java.util.Iterator;
/**
 * @author (c) 2009, Harald R. Haberstroh 23.04.2009
 */
public interface ShoppingCart {

    /**
     * legt die übergebene Anzahl von Elementen in den Warenkorb
     *
     * @param anItem
     *          Element
     * @param quantity
     *          Anzahl
     * @throws NegativeCountException
     *           negative Anzahl gibt's nicht
     */
    public void addItems(Item anItem, int quantity) throws NegativeCountException;

    /**
     * entfernt die Anzahl von Elementen vom Warenkorb.
     *
     * @param anItem
     *          welches Element
     * @param quantity
     *          Anzahl
     * @throws NegativeCountException
     *           negative Anzahl gibt's nicht
     * @throws NoSuchItemException 
     *           das Element existiert nicht im Warenkorb
     */
    public void deleteItems(Item anItem, int quantity)
         throws NegativeCountException, NoSuchItemException;

    /**
     * wieviele Element gibt's überhaupt
     *
     * @return Anzahl Elemente
     */
    public int itemCount();

    /**
     * Iterator für alle Elemente (siehe Collection-API).
     *
     * @return Iterator über alle Elemente
     */
    public Iterator<Item> iterator();
}

Denken Sie bei der Erstellung der Tests an Grenzfälle, Sonderfälle und erst dann an den "Normalfall".

Links:

  1. Testen mit JUnit
  2. Softwaretest

Labels: , , ,


Montag, 18. November 2013

 

Römische Zahlen umwandeln (POS1: 2BHIF)

Abgabename: 2013_2bhif_aufgabe6_name_vorname.tgz

Römische Zahlen

Schreiben Sie eine Klasse RomanNumber, welche es erlaubt, mit römischen Zahlen zu rechnen bzw. römische Zahlen in ganze Zahlen und umgekehrt umzurechnen. Schreiben Sie dazu Methoden zum Umrechnen von ganzen Zahlen (1 bis 3000) in Römische Zahlen und umgekehrt. Die römischen Ziffern haben folgende Bedeutung:

I ...    1
V ...    5
X ...   10
L ...   50
C ...  100
D ...  500
M ... 1000
Beachten Sie, dass nur jeweils drei gleiche Ziffern hintereinander geschrieben werden. Stattdessen wird die nächst größere Einheit benutzt und eine Einheit abgezogen (XC = 90, XCIX = 99, IX = 9, VIII = 8).
class RomanNumber:
    """Roman numbers.
    Internal representation is always the integer value.
    """

    def __init__(self, value):
        """Initialize with value.
        If type of value is int, than this is the integer value.
        If type of value is str, than this is a roman number, which has
        to be converted into the internal int-value"""
        pass

    def toRoman(self):
        """returns string with roman representation"""
        pass

    def toInt(self):
        """returns integer value of roman number"""
        pass

    def add(self, other):
        """add the value of other (RomanNumber) to own (self) value and
        return a new RomanNumber object."""
        pass

    def sub(self, other):
        """subtract the value of other (RomanNumber) from own (self) value and
        return a new RomanNumber object."""
        pass

    def mul(self, other):
        """multiply the value of other (RomanNumber) with own (self) value and
        return a new RomanNumber object."""
        pass

    def __str__(self):
        """returns the value like 'XXII (23)'"""
        pass

Ergänzen Sie dieses Gerüst zu einer funktionierenden Klasse und schreiben Sie ein Testprogramm mit fix programmierten Testfällen.

Schreiben Sie weiters ein zweites Modul, welches die Klasse RomanNumber importiert und jeweils eine Zeile der Art

zahl op zahl
einliest, die Operation op (+, - oder *) ausführt und das Ergebnis ganzzahlig und als Römische Zahl ausgibt. zahl ist jeweils eine ganze Zahl oder eine römische Zahl.

Beispielaufrufe:

~/work/tmp > python romancalc.py
>>> 24 + 27
LI (51)
>>> LI - 24
XXVII (27)
>>> LI - XXIV
XXVII (27)
>>>
~/work/tmp > 
Zum Schluss wurde EOF eingegeben (Strg-D), die Eingaben sind fett gedruckt.

Informationen finden Sie unter:

Labels: , , ,


Montag, 21. Oktober 2013

 

Testen und erweitern von text_analyzer.py (POS1: 2BHIF)

Abgabename: 2013_2bhif_aufgabe5_name_vorname.tgz

Ziel dieser Aufgabe ist es, fremden Code zu testen, zu verstehen und zu erweitern. Dazu werden Sie text_analyzer.py von zwei Mitschülern testen und um unten beschriebene Funktionalität erweitern. Schreiben Sie dazu ein Modul test_text_analyzer, welches die Funktionen vom Modul text_analyzer importiert und testet.

Protokollieren Sie die Testläufe und beschreiben Sie die eventuell gefundenen Fehler in einer Textdatei errors.txt. Haben Sie Fehler entdeckt, so korrigieren Sie diese, sodass die Tests fehlerfrei laufen.

Sollten Ihre Tests Fehler enthalten, so korrigieren sie diese ebenfalls (solche Fehler werden Sie u.U. erst finden, wenn Sie das zweite Programm testen).

Ergänzen Sie die Funktionalität von text_analyzer um die Funktion read_sentences(file), welche aus der geöffneten Datei file (d.h. die Datei muss vor dem Aufruf dieser Funktion geöffnet werden) Zeilen liest und in der selben Form wie die bereits bestehende Funktion input_sentences() liefert.

Ändern/Ergänzen Sie text_analyzer um ein main, welches prüft, ob Dateinamen auf der Kommandozeile angegeben wurden, diese Dateien der Reihe nach öffnet und das (End-)Ergebnis der Funktionen analyze_words(lst) und sort_letters(dic) ausgibt. Weiters sollen auch die Häufigkeiten der Worte, absteigend sortiert nach Häufigkeit (genau wie sort_letters(dic)) ausgegeben werden (braucht man eine neue Funktion?). Dabei soll die Ausgabe formatiert sein (also nicht nur die Listen bzw. Dictionaries ausgeben).
Werden keine Dateinamen angegeben, so ist wieder von der Konsole zu lesen.
Die Option -h gibt eine kurze Hilfe aus.

Die Einteilung der Gruppen finden Sie in der Schule unter
/home/teachers/hp/public/2bhif/2013_2bhif_aufgabe5_gruppeneinteilung.pdf.

Labels: , , ,


Sonntag, 4. November 2012

 

Testen und erweitern von text_analyzer.py (POS1: 2BHIF)

Abgabename: 2012_2bhif_aufgabe6_Name_Vorname.tgz

Ziel dieser Aufgabe ist es, fremden Code zu testen, zu verstehen und zu erweitern. Dazu werden Sie text_analyzer.py von zwei Mitschülern testen und um unten beschriebene Funktionalität erweitern. Schreiben Sie dazu ein Modul test_text_analyzer, welches die Funktionen vom Modul text_analyzer importiert und testet.

Protokollieren Sie die Testläufe und beschreiben Sie die eventuell gefundenen Fehler in einer Textdatei errors.txt. Haben Sie Fehler entdeckt, so korrigieren Sie diese, sodass die Tests fehlerfrei laufen.

Sollten Ihre Tests Fehler enthalten, so korrigieren sie diese ebenfalls (solche Fehler werden Sie u.U. erst finden, wenn Sie das zweite Programm testen).

Ergänzen Sie die Funktionalität von text_analyzer um die Funktion read_sentences(file), welche aus der geöffneten Datei file (d.h. die Datei muss vor dem Aufruf dieser Funktion geöffnet werden) Zeilen liest und in der selben Form wie die bereits bestehende Funktion input_sentences() liefert.

Ändern/Ergänzen Sie text_analyzer um ein main, welches prüft, ob Dateinamen auf der Kommandozeile angegeben wurden, diese Dateien der Reihe nach öffnet und das (End-)Ergebnis der Funktionen analyze_words(lst) und sort_letters(dic) ausgibt. Weiters sollen auch die Häufigkeiten der Worte, absteigend sortiert nach Häufigkeit (genau wie sort_letters(dic)) ausgegeben werden (braucht man eine neue Funktion?). Dabei soll die Ausgabe formatiert sein (also nicht nur die Listen bzw. Dictionaries ausgeben).
Werden keine Dateinamen angegeben, so ist wieder von der Konsole zu lesen.
Die Option -h gibt eine kurze Hilfe aus.

Die Einteilung der Gruppen finden Sie in der Schule unter
/home/teachers/hp/public/2bhif/2012_2bhif_aufgabe6_gruppeneinteilung.pdf.

Labels: , , ,


This page is powered by Blogger. Isn't yours?

Abonnieren Posts [Atom]