Unmittelbares, persönliches Feedback war seit den ersten Kursen ein Kernstück des Lernerlebnisses auf DataCamp. Wenn Lernende Code mit einem Fehler einreichen, erfahren sie, wo der Fehler liegt und wie sie ihn beheben können. Probier es selbst im kostenlosen Introduction to R Kurs aus. Der folgende Screenshot stammt aus unserem Intermediate R Kurs.

Um Einsendungen zu prüfen und Feedback zu erzeugen, enthält jede Übung auf DataCamp einen sogenannten Submission Correctness Test, kurz SCT.
Der SCT ist ein Skript mit maßgeschneiderten Tests. Es bewertet den eingereichten Code sowie die Ausgaben und Variablen, die damit erzeugt wurden. Für jede Sprache auf DataCamp haben wir ein passendes Open-Source-Paket entwickelt, mit dem sich all diese Elemente einer Abgabe einfach verifizieren lassen. Für R-Übungen heißt dieses Paket testwhat. Im Lauf der Jahre haben wir zahlreiche Funktionen ergänzt, um:
- Variablenzuweisungen zu prüfen
- Funktionsaufrufe und deren Ergebnisse zu prüfen
- if-Anweisungen, for- und while-Schleifen zu prüfen
- Funktionsdefinitionen zu prüfen
- zu prüfen, ob die richtigen Pakete geladen sind
- die vom Lernenden erzeugte Ausgabe zu prüfen
- ggplot- und ggvis-Plotaufrufe zu prüfen
- ...
Wenn diese Prüf-Funktionen einen Fehler entdecken, erzeugen sie automatisch eine aussagekräftige Rückmeldung, die Lernende direkt auf das Problem hinweist. Du kannst außerdem eigene Feedbacktexte angeben, die die automatisch generierten Nachrichten überschreiben.
Historisch war testwhat eng mit unserem proprietären Backend verknüpft, das R-Code auf den Servern von DataCamp ausführt. Obwohl testwhat immer Open Source war, funktionierte es ohne dieses Backend nicht gut und ließ sich nur im Kontext von DataCamp nutzen. Heute kann testwhat jedoch unabhängig eingesetzt werden und unterstützt weitere Anwendungsfälle. Du kannst alles nutzen, was testwhat bietet, um Abgaben zu prüfen – auch wenn dein Unterrichtsformat ganz anders ist als das von DataCamp. Installiere das Paket von GitHub:
library(remotes) # devtools funktioniert ebenso
install_github('datacamp/testwhat')
Als kurze Demo: Angenommen, du bittest Lernende, eine Variable x mit dem Wert 5 anzulegen. Eine String-Repräsentation der idealen Lösung sähe so aus:
solution_code <- 'x <- 5'
Nehmen wir nun an, die Abgabe setzt x fälschlicherweise auf einen Vektor mit zwei Werten. Das ließe sich so kodieren:
student_code <- 'x <- c(4, 5)'
testwhat enthält eine Funktion namens setup_state(), die die Abgabe und die Musterlösung in separaten Umgebungen ausführt und dabei Ausgaben und Fehlermeldungen der Lernenden erfasst. All diese Informationen landen im sogenannten exercise state, den du mit ex() abrufen kannst:
library(testwhat)
setup_state(stu_code = student_code,
sol_code = solution_code)
ex()
## <RootState>
Diesen Exercise State kannst du per Pipe-Syntax aus magrittr an die Vielzahl von Prüf-Funktionen in testwhat übergeben. Um zu überprüfen, ob die Variable x definiert wurde, nutzt du check_object():
ex() %>% check_object('x')
## <ObjectState>
Dieser Code läuft ohne Fehler, weil die Variable x tatsächlich existiert. Um weiter zu prüfen, ob x auch korrekt definiert wurde, verwendest du check_equal():
ex() %>% check_object('x') %>% check_equal()
## Error in check_that(is_equal(student_obj, solution_obj, eq_condition), : The contents of the variable `x` aren't correct. It has length 2, while it should have length 1.
Hier tritt ein Fehler auf. check_equal() erkennt, dass der Wert von x in der Lernumgebung (ein Vektor) nicht mit dem Wert von x in der Lösungsumgebung (eine einzelne Zahl) übereinstimmt. Beachte, dass die Fehlermeldung verständlich beschreibt, wo das Problem liegt.
Das obige Beispiel war interaktiv: Du setzt den State auf und tippst dann Ketten von Prüf-Funktionen. Auf höherer Ebene kannst du run_until_fail() verwenden, um die Prüf-Logik zu kapseln. Damit wird dein Testbündel so lange ausgeführt, bis ein Test fehlschlägt:
library(testwhat)
setup_state(stu_code = 'x <- 4',
sol_code = 'x <- 5')
res <- run_until_fail({
ex() %>% check_object('x') %>% check_equal()
})
res$correct
## [1] FALSE
res$message
## [1] "The contents of the variable `x` aren't correct."
Dieser grundlegende Ansatz – einen Exercise State mit Abgabe und Lösung erzeugen und dann run_until_fail() nutzen, um einen Testkatalog auszuführen – lässt sich leicht in einen Autograding-Workflow integrieren, der zu deinen Anforderungen passt. Angenommen, deine Lernenden haben ihre Aufgaben als R-Skripte eingereicht, die du in den Ordner submissions auf deinem Rechner heruntergeladen hast (wir haben den Ordner mit Beispieldaten gefüllt). Im Ordner submissions liegen mehrere R-Skripte. Jedes Skript enthält eine Abgabe:
dir('submissions')
## [1] "student_a.R" "student_b.R" "student_c.R" "student_d.R" "student_e.R"
## [6] "student_f.R" "student_g.R" "student_h.R" "student_i.R" "student_j.R"
readLines('submissions/student_a.R')
## [1] "x <- 4"
readLines('submissions/student_b.R')
## [1] "x <- 5"
Jetzt können wir alle Abgaben durchgehen und ein data.frame erzeugen, das für jede Person angibt, ob die Lösung korrekt war oder nicht:
library(testwhat)
folder_name <- 'submissions'
all_files <- file.path(folder_name, dir(folder_name))
student_results <- sapply(all_files, function(file) {
student_code <- readLines(file)
setup_state(sol_code = 'x <- 5',
stu_code = student_code)
res <- run_until_fail({
ex() %>% check_object('x') %>% check_equal()
})
res$correct
})
results_df <- data.frame(name = all_files, correct = student_results,
row.names = NULL, stringsAsFactors = FALSE)
results_df
## name correct
## 1 submissions/student_a.R FALSE
## 2 submissions/student_b.R TRUE
## 3 submissions/student_c.R TRUE
## 4 submissions/student_d.R TRUE
## 5 submissions/student_e.R FALSE
## 6 submissions/student_f.R TRUE
## 7 submissions/student_g.R FALSE
## 8 submissions/student_h.R FALSE
## 9 submissions/student_i.R TRUE
## 10 submissions/student_j.R TRUE
Diese kleine Demo ist noch etwas rudimentär, aber sie zeigt das Prinzip: Mit etwas R-Code, um die passenden Eingaben für setup_state() zu bauen, kannst du sämtliche Prüf-Funktionen von testwhat nutzen. Die in run_until_fail() definierten Tests bewerten die Arbeit der Lernenden und erzeugen zugleich hilfreiches Feedback, das gezielt auf gemachte Fehler hinweist.
Um mehr über testwhat zu erfahren, besuche das GitHub-Repository oder die Paketdokumentation, erstellt mit pkgdown. Dort findest du Vignetten, die die Nutzung bestimmter Prüf-Funktionen erläutern, sowie eine Referenz mit allen Parametern. Melde gern Issues auf GitHub oder schreib an content-engineering@datacamp.com – wir freuen uns über Feedback! Viel Erfolg beim Unterrichten!
Dieser Blogbeitrag wurde mit RMarkdown erstellt. Den Quellcode findest du hier.
