Dynamischer Python Checker (JACK3): Unterschied zwischen den Versionen
(WIP: Python-Checker) |
(Finalisierung) |
||
Zeile 1: | Zeile 1: | ||
Der [[Python (JACK3)|Aufgabentyp Python]] lässt sich automatisiert bewerten, indem Testfälle ausgeführt werden. Diese können z. B. einen erwarteter Wert mit dem tatsächlichen Wert vergleichen. Der Python-Checker von JACK3 kann nicht nur Punktzahlen und Feedback zurückgeben, sondern auch Traces aufzeichnen (welche Zeilen ausgeführt wurden und wie die Variablenbelegung beim Testfall war). Es lassen sich beliebig komplexe Testfälle und auch zufallsbasierte Tests schreiben sowie passgenaues Feedback, programmiert in Python, erzeugen. | |||
Der | {{Hinweis|In diesem Artikel werden [https://docs.python.org/3/tutorial/index.html grundlegende Python-Kenntnisse] vorausgesetzt.}} | ||
Der Checker arbeitet auf Python 3.11. Aktuell ist es nicht möglich, eigene Module zum Check hinzuzufügen oder Pakete aus dem Python Package Index (PyPI) (über <code>pip</code>) zu laden. Das Paket [https://pypi.org/project/pandas/ pandas] ist vorinstalliert und kann durch den Testtreiber geladen werden, ansonsten sind ausschließlich Pakete der [https://docs.python.org/3.11/library/index.html Python-Standardbibliothek] nutzbar. | |||
=== Unterstützte Aufgabenstellungen === | |||
Der dynamische Python-Checker ist darauf ausgelegt, Funktionsaufrufe aufzuzeichnen und ihre Rückgabewerte zu prüfen. Dies funktioniert am besten mit folgenden Aufgabenstellungen: | |||
* Schreiben Sie eine parameterlose Funktion, die ... zurückgibt. | |||
* Schreiben Sie eine Funktion, die ... erwartet und ... zurückgibt. | |||
* Schreiben Sie eine Funktion mit x Parametern, die mit dem ersten Parameter ... macht. (Um die Funktion zu prüfen, muss der Typ des ersten Parameters mutierbar sein, z. B. eine Liste.) | |||
'''Beispiel''': ''Definieren sie eine Funktion add. Die Funktion soll zwei Parameter entgegennehmen und das Ergebnis der Addition zurückgeben.'' Die erwartete Musterlösung für diesen Fall wäre:<syntaxhighlight lang="python3"> | |||
def add(a, b): | |||
return a + b | |||
</syntaxhighlight>Testfälle (s.u.) können diese Funktion dann mit verschiedenen Werten aufrufen und das Ergebnis prüfen. | |||
===Aufbau eines Testtreibers=== | |||
Grundsätzlich ist ein Testtreiber ein einzelnes Modul mit einer oder mehreren [https://docs.python.org/3.11/tutorial/controlflow.html#defining-functions parameterlosen Funktionen] ('''Testfälle'''), die nacheinander ausgeführt werden. In der Regel importiert der Testtreiber dabei das Modul mit dem eingereichten (zu testenden) Code. Dessen Name [[Python (JACK3)#Feedback|wird im UI als "Modul-Pfad für studentischen Code"]] festgelegt. | |||
Damit die Traces der Testfälle korrekt aufgezeichnet werden, wird jeder Testfall mit dem [https://book.pythontips.com/en/latest/decorators.html Decorator] <code>decorator</code> aus dem vorgegebenen <code>Communicator</code>-Modul gekennzeichnet. Der folgende Code zeigt ein Beispiel mit zwei Testfällen, jeweils ohne Inhalt:<syntaxhighlight lang="python3" line="1"> | |||
import Communicator | |||
import Trace | |||
import studentcode as s | |||
@Communicator.decorator | |||
def testcase1(): | |||
# TODO so something with s ... | |||
pass | |||
@Communicator.decorator | |||
def testcase2(): | |||
# TODO so something with s ... | |||
pass | |||
if __name__ == '__main__': | |||
print('Running test case 1...') | |||
testcase1() | |||
print('Running test case 2 ...') | |||
testcase2() | |||
</syntaxhighlight> | |||
=== API zum Zurückmelden von Ergebnissen === | ===API zum Zurückmelden von Ergebnissen=== | ||
Innerhalb eines Testfalls werden Ergebnisse über das Modul <code>Trace</code> zurückgeliefert. Dieses Modul sammelt alle Punktzahlen und Feedback auf und berichtet diese am Ende der Ausführung. Es bietet folgende Funktion:<syntaxhighlight lang="python3"> | |||
def printResult(result: int, feedback: str = None): | def printResult(result: int, feedback: str = None): | ||
""" | """ | ||
Reports a result | Reports a result. | ||
:param result: Points which are reported. Must be between 0 and 100 (both inclusive). | :param result: Points which are reported. Must be between 0 and 100 (both inclusive). | ||
Zeile 19: | Zeile 52: | ||
""" | """ | ||
pass | pass | ||
</syntaxhighlight> | </syntaxhighlight>{{Wichtig|In jedem Testfall muss <code>printResult</code> genau ein Mal tatsächlich aufgerufen werden!}} | ||
=== Schreiben von Testfällen === | |||
Der Checker nutzt für das Tracing eine spezielle Kontrollflussanalyse, basierend auf Pythons [https://docs.python.org/3.11/reference/simple_stmts.html#the-assert-statement <code>assert</code>-Schlüsselwort] und Exceptions. Mit <code>assert</code> lassen sich Ausdrücke testen, die resultierende Exception lässt sich anschließend fangen und in Feedback umwandeln. | |||
Ein möglicher Testfall 1 für das obige Beispiel wäre dementsprechend:<syntaxhighlight lang="python3" line="1" start="5"> | |||
@Communicator.decorator | |||
def testcase1(): | |||
try: | |||
# Berechnen des Ergebnisses mit dem "studentcode": | |||
result = s.add(1, 0) | |||
# zu prüfender Ausdruck: | |||
assert result == 1 | |||
# Bei Erfolg: +25 Punkte | |||
Trace.printResult(25) | |||
except Exception: | |||
# Bei Misserfolg: +0 Punkte mit Feedback-Nachricht | |||
Trace.printResult(0, f"Erwartete Summe: 1, tatsächlich: {result}.") | |||
</syntaxhighlight>Das Tracing reagiert auf alle Arten von Exceptions und zeigt im Falle eines <code>AssertionError</code>s (entweder händisch geworfen oder über <code>assert</code>) eine generische Fehlermeldung an, die mitteilt, dass der Testfall nicht bestanden wurde, sofern kein benutzerdefiniertes Feedback (zweiter Parameter von <code>printResult</code>) vorgegeben wurde. | |||
Pro Testtreiber werden die Punkte aller Testfälle aufsummiert. Bei einer gleichen Gewichtung von vier Testfällen wird jeder Testfall also 25 Punkte im Erfolg zurückmelden. Die summierten Punkte müssen zwischen 0 und 100 (jeweils inklusiv) liegen. | |||
[[Kategorie:Benutzerhandbuch]] | [[Kategorie:Benutzerhandbuch]] | ||
[[Kategorie:Checker]] | |||
Version vom 9. Oktober 2024, 15:05 Uhr
Der Aufgabentyp Python lässt sich automatisiert bewerten, indem Testfälle ausgeführt werden. Diese können z. B. einen erwarteter Wert mit dem tatsächlichen Wert vergleichen. Der Python-Checker von JACK3 kann nicht nur Punktzahlen und Feedback zurückgeben, sondern auch Traces aufzeichnen (welche Zeilen ausgeführt wurden und wie die Variablenbelegung beim Testfall war). Es lassen sich beliebig komplexe Testfälle und auch zufallsbasierte Tests schreiben sowie passgenaues Feedback, programmiert in Python, erzeugen.
Hinweis: In diesem Artikel werden grundlegende Python-Kenntnisse vorausgesetzt.
Der Checker arbeitet auf Python 3.11. Aktuell ist es nicht möglich, eigene Module zum Check hinzuzufügen oder Pakete aus dem Python Package Index (PyPI) (über pip
) zu laden. Das Paket pandas ist vorinstalliert und kann durch den Testtreiber geladen werden, ansonsten sind ausschließlich Pakete der Python-Standardbibliothek nutzbar.
Unterstützte Aufgabenstellungen
Der dynamische Python-Checker ist darauf ausgelegt, Funktionsaufrufe aufzuzeichnen und ihre Rückgabewerte zu prüfen. Dies funktioniert am besten mit folgenden Aufgabenstellungen:
- Schreiben Sie eine parameterlose Funktion, die ... zurückgibt.
- Schreiben Sie eine Funktion, die ... erwartet und ... zurückgibt.
- Schreiben Sie eine Funktion mit x Parametern, die mit dem ersten Parameter ... macht. (Um die Funktion zu prüfen, muss der Typ des ersten Parameters mutierbar sein, z. B. eine Liste.)
Beispiel: Definieren sie eine Funktion add. Die Funktion soll zwei Parameter entgegennehmen und das Ergebnis der Addition zurückgeben. Die erwartete Musterlösung für diesen Fall wäre:
def add(a, b):
return a + b
Testfälle (s.u.) können diese Funktion dann mit verschiedenen Werten aufrufen und das Ergebnis prüfen.
Aufbau eines Testtreibers
Grundsätzlich ist ein Testtreiber ein einzelnes Modul mit einer oder mehreren parameterlosen Funktionen (Testfälle), die nacheinander ausgeführt werden. In der Regel importiert der Testtreiber dabei das Modul mit dem eingereichten (zu testenden) Code. Dessen Name wird im UI als "Modul-Pfad für studentischen Code" festgelegt.
Damit die Traces der Testfälle korrekt aufgezeichnet werden, wird jeder Testfall mit dem Decorator decorator
aus dem vorgegebenen Communicator
-Modul gekennzeichnet. Der folgende Code zeigt ein Beispiel mit zwei Testfällen, jeweils ohne Inhalt:
import Communicator
import Trace
import studentcode as s
@Communicator.decorator
def testcase1():
# TODO so something with s ...
pass
@Communicator.decorator
def testcase2():
# TODO so something with s ...
pass
if __name__ == '__main__':
print('Running test case 1...')
testcase1()
print('Running test case 2 ...')
testcase2()
API zum Zurückmelden von Ergebnissen
Innerhalb eines Testfalls werden Ergebnisse über das Modul Trace
zurückgeliefert. Dieses Modul sammelt alle Punktzahlen und Feedback auf und berichtet diese am Ende der Ausführung. Es bietet folgende Funktion:
def printResult(result: int, feedback: str = None):
"""
Reports a result.
:param result: Points which are reported. Must be between 0 and 100 (both inclusive).
:param feedback: Optional Feedback presented to the user.
"""
pass
Wichtig: In jedem Testfall muss printResult
genau ein Mal tatsächlich aufgerufen werden!
Schreiben von Testfällen
Der Checker nutzt für das Tracing eine spezielle Kontrollflussanalyse, basierend auf Pythons assert
-Schlüsselwort und Exceptions. Mit assert
lassen sich Ausdrücke testen, die resultierende Exception lässt sich anschließend fangen und in Feedback umwandeln.
Ein möglicher Testfall 1 für das obige Beispiel wäre dementsprechend:
@Communicator.decorator
def testcase1():
try:
# Berechnen des Ergebnisses mit dem "studentcode":
result = s.add(1, 0)
# zu prüfender Ausdruck:
assert result == 1
# Bei Erfolg: +25 Punkte
Trace.printResult(25)
except Exception:
# Bei Misserfolg: +0 Punkte mit Feedback-Nachricht
Trace.printResult(0, f"Erwartete Summe: 1, tatsächlich: {result}.")
Das Tracing reagiert auf alle Arten von Exceptions und zeigt im Falle eines AssertionError
s (entweder händisch geworfen oder über assert
) eine generische Fehlermeldung an, die mitteilt, dass der Testfall nicht bestanden wurde, sofern kein benutzerdefiniertes Feedback (zweiter Parameter von printResult
) vorgegeben wurde.
Pro Testtreiber werden die Punkte aller Testfälle aufsummiert. Bei einer gleichen Gewichtung von vier Testfällen wird jeder Testfall also 25 Punkte im Erfolg zurückmelden. Die summierten Punkte müssen zwischen 0 und 100 (jeweils inklusiv) liegen.