it-praxisportal/09_eigene_unit_tests_schreiben/musterloesung.py

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)