Kurs Python richtig lernen/Unit Testing: Unterschied zwischen den Versionen
Zeile 16: | Zeile 16: | ||
$ nosetests | $ nosetests | ||
− | Als Output bekommen Sie eine kleine Statistik inkl. dem Fehlerstatus (OK/NOK). Möchten Sie detailliertere | + | Als Output bekommen Sie eine kleine Statistik inkl. dem Fehlerstatus (OK/NOK). Möchten Sie detailliertere Infos (welche Tests durchgeführt wurden), dann verwenden Sie die Option ''-v'' (verbose). |
Wie Sie sehen, müssen wir nirgends angeben, welche Funktionen und Module Nose als Testfunktionen betrachtet. Für Funktionen und Module gibt es eine einfache Namenskonvention, die durch folgende regular expression beschrieben ist: ((?:^|[b_.-])[Tt]est) | Wie Sie sehen, müssen wir nirgends angeben, welche Funktionen und Module Nose als Testfunktionen betrachtet. Für Funktionen und Module gibt es eine einfache Namenskonvention, die durch folgende regular expression beschrieben ist: ((?:^|[b_.-])[Tt]est) |
Version vom 12. September 2012, 15:02 Uhr
Inhaltsverzeichnis
Übung "Unit Testing mit Python und Nose"
In dieser Übung lernen Sie Unit Testing mit dem Python Test Runner Nose.
Geschätzter Zeitaufwand für diese Übung: ca. 2h.
Einstieg
Um Nose kennenzulernen starten wir mit einem Beispiel. Speichern Sie den folgenden Unit test in einem File "test_42.py":
def test_life_the_universe_and_everything(): assert 42 == 42
Führen Sie diesen Test wiefolgt aus:
$ nosetests
Als Output bekommen Sie eine kleine Statistik inkl. dem Fehlerstatus (OK/NOK). Möchten Sie detailliertere Infos (welche Tests durchgeführt wurden), dann verwenden Sie die Option -v (verbose).
Wie Sie sehen, müssen wir nirgends angeben, welche Funktionen und Module Nose als Testfunktionen betrachtet. Für Funktionen und Module gibt es eine einfache Namenskonvention, die durch folgende regular expression beschrieben ist: ((?:^|[b_.-])[Tt]est)
Manchmal benötigen Sie für Ihre Unit Tests Fixtures. Diese können Sie wiefolgt definieren:
def test_life_the_universe_and_everything(): assert 42 != 42 def setUp(): print "Setup" def tearDown(): print "tearDown" test_life_the_universe_and_everything.setUp = setUp test_life_the_universe_and_everything.tearDown = tearDown
Führen Sie dieses Beispiel aus und verifizieren Sie, dass die Ausgaben Ihren Erwartungen entsprechen (setup, failing test, teardown).
Nose erlaubt es Ihnen - neben Testfunktionen - Ihre Tests auch innerhalb einer Klasse zu schreiben (gemäss xUnit). Das gleiche Beispiel wie vorhin:
class Test42: def setUp(self): print "Setup" def tearDown(self): print "tearDown" def test_life_the_universe_and_everything(self): assert 42 != 42
Tip: Wundern Sie sich nicht, wenn Sie Ausgaben in Ihren Unit Tests mit print nicht auf Ihrer Konsole sehen. Nose fängt alle Ausgaben auf stdout auf und zeigt diese nur bei fehlgeschlagenen Tests an. Dieses Verhalten kann mit der Option -s unterbunden werden.
Um das Werfen von Exceptions testen zu können, benutzen Sie folgende Nose Decoration:
from nose.tools import raises @raises(ZeroDivisionError) def test_rational_zero_denominator_raises_error(): r = Rational(3, 0)
Weitere Informationen zu Nose finden Sie hier.
Aufgabe 1 - Bank Account
Testen Sie folgenden Code mit Nose (denken Sie auch an das Testen von Exceptions):
class BankAccount(object): def __init__(self, initial_balance=0): self.balance = initial_balance def deposit(self, amount): self.balance += amount def withdraw(self, amount): if amount > self.balance: raise ValueError('Amount is higher than current balance') self.balance -= amount
Aufgabe 2 - Rationale Zahlen
Testen Sie folgenden Code mit Nose (denken Sie auch an das Testen von Exceptions):
def gcd(a, b): if b == 0: return a else: return gcd(b, a % b) class Rational: def __init__(self, n, d): if d == 0: raise ValueError("Denominator must not be zero.") else: g = gcd (n, d) self.n = n / g self.d = d / g def __add__(self, other): return Rational(self.n * other.d + other.n * self.d, self.d * other.d) def __sub__(self, other): return Rational(self.n * other.d - other.n * self.d, self.d * other.d) def __mul__(self, other): return Rational(self.n * other.n, self.d * other.d) def __div__(self, other): return Rational(self.n * other.d, self.d * other.n) def __str__(self): return "%d/%d" % (self.n, self.d) def __float__(self): return float(self.n) / float(self.d) def __eq__(self, other): if self is other: return True elif type(self) != type(other): return False else: return self.n == other.n and self.d == other.d