Mittwoch, 8. Oktober 2014
Musterlösung zu Unit-Tests
Folgende Grenzfälle werden getestet:
- 0 Elemente aufnehmen, Anzahl muss gleich bleiben
- 0 Elemente löschen, Anzahl muss gleich bleiben
- negative Anzahl Elemente aufnehmen, Exception
- negative Anzahl Elemente löschen, Exception
- nicht vorhandenes Element löschen, Exception
- 10 Elemente aufnehmen, Anzahl testen
- 10 Elemente aufnehmen, Ergebnis des Iterators testen
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: Java, Lösung, POS1-3, Testen
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:
Labels: Aufgabe, Java, POS1-2, Testen
Montag, 18. November 2013
Römische Zahlen umwandeln (POS1: 2BHIF)
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 ... 1000Beachten 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 zahleinliest, 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 >
Informationen finden Sie unter:
Labels: Aufgabe, POS1-2, Python, Testen
Montag, 21. Oktober 2013
Testen und erweitern von text_analyzer.py (POS1: 2BHIF)
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: Aufgabe, POS1-2, Python, Testen
Sonntag, 4. November 2012
Testen und erweitern von text_analyzer.py (POS1: 2BHIF)
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: allgemeines, POS1-2, Python, Testen
Abonnieren Posts [Atom]