Level 6: Mehr Tests #
Unittests in einer eigenen Datei #
Gerade bei noch umfangreicheren Tests sollen die Testfälle nicht mehr in den Docstring geschrieben werden. Anstattdessen lässt sich eine eigene Testklasse schreiben (zu Klassen später mehr), in der die Tests aufgeschrieben werden.
Lege Dir zwei Dateien ccsort.py
und sorttest.py
an und speichere sie in einem gemeinsamen Ordner ab. Übernimm den Code aus der Übung unten. Sieh Dir zunächst die Datei sorttest.py
in Thonny an, und bearbeite dann die erste Aufgabe, die in ccsort.py
angegeben ist.
Was passiert hier? #
Lass Dich nicht vom Außenrum irritieren: für den Moment ist nur die Anweisung assertEqual(…)
wichtig. In einer Reihe von Testfällen (die Alle mit der Zeichenkette test
beginnen müssen) werden verschiedene Dinge überprüft. Dabei wird der Methode assertEqual()
jeweils die zu testenden Funktion (hier: ccsort()
im Modul ccsort
, alsoccsort.ccsort()
) mit einer Testeingabe ([]
, [3,5,2,1]
, usw.) übergeben, und außerdem das erwartete Ergebnis. Stimmen beide überein, war der Test erfolgreich, gibt es Abweichungen, schlägt der Test fehl. Im Idealfall (wenn alle Tests in Ordnung sind) wird (fast) nichts angezeigt, nämlich nur, dass die Tests ausgeführt wurden. Andernfalls werden die Unterschiede gezeigt (und Du als Programmierer:in hast wieder etwas zu tun…)
An die Arbeit #
In den Tests wird die Rückgabe einer sortierten Liste erwartet – das ist ein sehr wichtiges Thema in der Informatik, da sehr oft große Datenmengen nur sortiert gut zu verarbeiten sind. Es gibt daher bereits viele Rezepte, wie sich Sortieren auf möglichst elegante Weise umsetzen ließe. Überlege aber zunächst selbst, welche Aktionen nötig sind, um die Testfälle zu sortieren.
Wenn Du etwas Anregung brauchst, schau Dir doch einmal dieses Video an:
Teste Deine Implementierung, indem Du sorttest.py
laufen lässt.
Übung: Sortieren! #
- Lass die Datei sorttest.py laufen, einmal mit und einmal ohne die Zeile
liste.sort()
und sieh Dir das Ergebnis der Tests an. - Überlege Dir, wie sich eine Liste (aufsteigend) sortieren ließe, und versuche, Deine Idee zu implementieren. Sieh Dir im Zweifel die Testfälle in sorttest.py an. (Auf die eingebaute Funktion
sort()
soll natürlich verzichtet werden…)
# sorttest.py
import unittest
import ccsort
class SortTest(unittest.TestCase):
def testSortLeer(self):
self.assertEqual(ccsort.ccsort([]), [])
def testSortEinElement(self):
self.assertEqual(ccsort.ccsort([42]), [42])
def testSortGeradeAnzahl(self):
self.assertEqual(ccsort.ccsort([3,5,2,1]), [1,2,3,5])
self.assertEqual(ccsort.ccsort([1,1,2,2]), [1,1,2,2])
def testSortUngeradeAnzahl(self):
self.assertEqual(ccsort.ccsort([5,4,3,2,1]), [1,2,3,4,5])
self.assertEqual(ccsort.ccsort([9,4,5,0,2]), [0,2,4,5,9])
def testSortSortiert(self):
self.assertEqual(ccsort.ccsort([1,2,5,7,8]), [1,2,5,7,8])
if __name__ == '__main__':
unittest.main()
# ccsort.py
def ccsort(liste):
# liste.sort()
return liste
Im Im- und Export-Geschäft
Wenn du längere Programme schreibst, wirst du deinen Code vielleicht auf verschiedene Dateien aufteilen wollen. Dazu kannst du den
import
-Befehl nutzen, den wir an verschiedenen Stellen schon verwendet haben – diesmal, um dein eigenes Modul einzubinden!import ccsort
macht hier genau dies!
Tipp 1
Listenelemente lassen sich elegant in einer Zeile vertauschen:
>>> meine_liste = [1, 2, 3, 4]
>>> meine_liste
[1, 2, 3, 4]
>>> meine_liste[1], meine_liste[0] = meine_liste[0], meine_liste[1]
>>> meine_liste
[2, 1, 3, 4]
(Hintergrund ist das Unpacking von Tupeln – zunächst wird die rechte Seite »eingepackt«, und links in umgedrehter Reihenfolge wieder »ausgepackt«.)
Tipp 2
Ähnlich wie beim Palindrom-Test in der letzten Übung, kann eine Liste von der Länge eins oder kleiner als sortiert gelten:
def ccsort(liste):
if len(liste) > 1:
# …hier kommt der Sortiercode hin
return liste
Tipp 3
Vielleicht ist dir aufgefallen, dass die (getanzten) Vergleiche, die im Video von links nach rechts wandern, immer weniger werden – die höchste Zahl wandert gleich zu Beginn nach ganz rechts, und dreht sich dort um. Sie wird nun nicht mehr verglichen.
Dies lässt sich mit einer kleiner werdenden oberen Grenze programmieren, etwa so:
obere_grenze = len(liste) - 1
while obere_grenze > 0:
# …hier kommen die weiteren Vergleiche hin
obere_grenze -= 1
Tipp 4
Um mit einem Index durch die Liste zu wandern, bietet sich unsere range
-Funktion an. Nur wenn der linke Wert größer als der rechte ist, werden die beiden vertauscht:
for index in range(obere_grenze):
if liste[index] > liste[index + 1]:
liste[index], liste[index + 1] = liste[index + 1], liste[index]
Lösungsvorschlag
# ccsort.py
def ccsort(liste):
if len(liste) > 1:
obere_grenze = len(liste) - 1
while obere_grenze > 0:
for index in range(obere_grenze):
if liste[index] > liste[index + 1]:
liste[index], liste[index + 1] = liste[index + 1], liste[index]
obere_grenze -= 1
return liste
Das Sortieren ließe sich abbrechen, wenn in einem Durchgang festgestellt würde, dass die Liste bereits sortiert ist. Darauf wurde hier aus Gründen der Übersichtlichkeit verzichtet.