149 lines
5.1 KiB
Python
149 lines
5.1 KiB
Python
"""
|
|
Kapitel 09: Eigene Unit Tests schreiben & TDD 🧪
|
|
================================================
|
|
Musterlösung: Vollständige Test-Suite für Taschenrechner und Bankkonto.
|
|
"""
|
|
|
|
import math
|
|
import unittest
|
|
from typing import List
|
|
|
|
|
|
# ==============================================================================
|
|
# Vorgegebene Klassen: Taschenrechner & Bankkonto
|
|
# ==============================================================================
|
|
|
|
class Taschenrechner:
|
|
"""Einfacher Taschenrechner für mathematische Grundoperationen."""
|
|
|
|
def __init__(self):
|
|
self.speicher: float = 0.0
|
|
|
|
def add(self, a: float, b: float) -> float:
|
|
return a + b
|
|
|
|
def sub(self, a: float, b: float) -> float:
|
|
return a - b
|
|
|
|
def mul(self, a: float, b: float) -> float:
|
|
return a * b
|
|
|
|
def div(self, a: float, b: float) -> float:
|
|
if b == 0:
|
|
raise ZeroDivisionError("Division durch Null ist nicht erlaubt!")
|
|
return a / b
|
|
|
|
def wurzel(self, a: float) -> float:
|
|
if a < 0:
|
|
raise ValueError("Wurzel aus negativen Zahlen ist im Reellen nicht definiert!")
|
|
return math.sqrt(a)
|
|
|
|
def speicher_plus(self, wert: float) -> None:
|
|
self.speicher += wert
|
|
|
|
def speicher_loeschen(self) -> None:
|
|
self.speicher = 0.0
|
|
|
|
|
|
class Bankkonto:
|
|
"""Modelliert ein Bankkonto mit Ein-, Auszahlungen und Überweisungen."""
|
|
|
|
def __init__(self, inhaber: str, kontostand: float = 0.0):
|
|
self.inhaber: str = inhaber
|
|
self.kontostand: float = float(kontostand)
|
|
self.transaktionen: List[float] = [float(kontostand)]
|
|
|
|
def einzahlen(self, betrag: float) -> None:
|
|
if betrag <= 0:
|
|
raise ValueError("Einzahlungsbetrag muss größer als 0 sein!")
|
|
self.kontostand += betrag
|
|
self.transaktionen.append(betrag)
|
|
|
|
def abheben(self, betrag: float) -> None:
|
|
if betrag <= 0:
|
|
raise ValueError("Auszahlungsbetrag muss größer als 0 sein!")
|
|
if betrag > self.kontostand:
|
|
raise ValueError("Nicht genügend Guthaben auf dem Konto!")
|
|
self.kontostand -= betrag
|
|
self.transaktionen.append(-betrag)
|
|
|
|
def ueberweisen(self, ziel_konto: "Bankkonto", betrag: float) -> None:
|
|
self.abheben(betrag)
|
|
ziel_konto.einzahlen(betrag)
|
|
|
|
|
|
# ==============================================================================
|
|
# Musterlösung: Die Unit-Test-Klassen
|
|
# ==============================================================================
|
|
|
|
class TestTaschenrechner(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
"""Wird vor JEDEM einzelnen Test ausgeführt."""
|
|
self.calc = Taschenrechner()
|
|
|
|
def test_01_grundrechenarten(self):
|
|
"""Testet Addition, Subtraktion und Multiplikation."""
|
|
self.assertEqual(self.calc.add(2, 3), 5)
|
|
self.assertEqual(self.calc.sub(10, 4), 6)
|
|
self.assertEqual(self.calc.mul(3, 7), 21)
|
|
|
|
def test_02_division_und_kommazahlen(self):
|
|
"""Testet normale Division und periodische Kommazahlen mit assertAlmostEqual."""
|
|
self.assertEqual(self.calc.div(10, 2), 5.0)
|
|
self.assertAlmostEqual(self.calc.div(10, 3), 3.3333, places=2)
|
|
|
|
def test_03_division_durch_null_exception(self):
|
|
"""Testet, dass bei Division durch 0 ein ZeroDivisionError geworfen wird."""
|
|
with self.assertRaises(ZeroDivisionError):
|
|
self.calc.div(10, 0)
|
|
|
|
def test_04_wurzel_negativ_exception(self):
|
|
"""Testet normale Wurzel und Exception bei negativen Zahlen."""
|
|
self.assertAlmostEqual(self.calc.wurzel(16), 4.0)
|
|
with self.assertRaises(ValueError):
|
|
self.calc.wurzel(-9)
|
|
|
|
def test_05_speicher_funktionen(self):
|
|
"""Testet speicher_plus und speicher_loeschen."""
|
|
self.assertEqual(self.calc.speicher, 0.0)
|
|
self.calc.speicher_plus(15.5)
|
|
self.calc.speicher_plus(4.5)
|
|
self.assertEqual(self.calc.speicher, 20.0)
|
|
self.calc.speicher_loeschen()
|
|
self.assertEqual(self.calc.speicher, 0.0)
|
|
|
|
|
|
class TestBankkonto(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
"""Erstellt zwei frische Konten vor jedem Test."""
|
|
self.k1 = Bankkonto("Alice", 100.0)
|
|
self.k2 = Bankkonto("Bob", 50.0)
|
|
|
|
def test_06_einzahlen_und_abheben(self):
|
|
"""Testet Ein- und Auszahlung sowie Transaktionshistorie."""
|
|
self.k1.einzahlen(50.0)
|
|
self.assertEqual(self.k1.kontostand, 150.0)
|
|
self.assertIn(50.0, self.k1.transaktionen)
|
|
|
|
self.k1.abheben(30.0)
|
|
self.assertEqual(self.k1.kontostand, 120.0)
|
|
self.assertIn(-30.0, self.k1.transaktionen)
|
|
|
|
def test_07_abheben_ueber_limit_exception(self):
|
|
"""Testet, dass Abheben von mehr als Kontostand einen ValueError auslöst."""
|
|
with self.assertRaises(ValueError):
|
|
self.k1.abheben(200.0)
|
|
|
|
def test_08_ueberweisung(self):
|
|
"""Testet erfolgreiche Überweisung zwischen zwei Konten."""
|
|
self.k1.ueberweisen(self.k2, 40.0)
|
|
self.assertEqual(self.k1.kontostand, 60.0)
|
|
self.assertEqual(self.k2.kontostand, 90.0)
|
|
self.assertIn(-40.0, self.k1.transaktionen)
|
|
self.assertIn(40.0, self.k2.transaktionen)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|