Directe en persoonlijke feedback staat sinds de eerste cursussen centraal in de leerervaring op DataCamp. Als studenten code indienen met een fout, krijgen ze te horen waar de fout zit en hoe ze die kunnen oplossen. Je kunt dit zelf uitproberen in onze gratis cursus Introduction to R. De onderstaande screenshot komt uit onze cursus Intermediate R.

Om inzendingen te controleren en feedback te genereren, bevat elke oefening op DataCamp een zogenaamde Submission Correctness Test, of SCT.
De SCT is een script met aangepaste tests dat de door studenten ingediende code beoordeelt en de output en variabelen die ze met hun code hebben aangemaakt. Voor elke taal die we op DataCamp doceren, hebben we een bijbehorend open-sourcepakket gebouwd om al deze elementen van een studenteninzending eenvoudig te verifiëren. Voor R-oefeningen heet dit pakket testwhat. Door de jaren heen hebben we veel functies toegevoegd om te:
- controleren of variabelen correct worden toegekend
- controleren of functieaanroepen en hun resultaten kloppen
- controleren op if-statements, for-loops en while-loops
- controleren op functiedefinities
- controleren of de juiste packages zijn geladen
- controleren of de door de student gegenereerde output klopt
- ggplot- en ggvis-plotaanroepen controleren
- ...
Wanneer deze controlefuncties een fout ontdekken, genereren ze automatisch een zinvolle feedbackmelding die studenten op hun vergissing wijst. Je kunt ook aangepaste feedbackberichten opgeven die deze automatisch gegenereerde berichten overschrijven.
Historisch gezien was testwhat nauw verbonden met onze eigen backend die R-code op de servers van DataCamp uitvoert. Hoewel testwhat altijd open source is geweest, werkte het zonder deze aangepaste backend niet goed en kon het alleen in de context van DataCamp worden gebruikt. Tegenwoordig kan testwhat echter zelfstandig worden gebruikt en ook andere toepassingen ondersteunen. Je kunt alles waar testwhat voor is gebouwd inzetten om studenteninzendingen te testen, zelfs als jouw onderwijsvorm heel anders is dan die van DataCamp. Je installeert het pakket vanaf GitHub:
library(remotes) # devtools works fine too
install_github('datacamp/testwhat')
Als snelle demo: stel dat je studenten vraagt om een variabele x te maken die gelijk is aan 5. Een stringversie van de ideale oplossing zou er zo uitzien:
solution_code <- 'x <- 5'
Stel nu dat de student een script heeft ingediend waarin x onjuist is ingesteld als een vector van twee waarden. Dat kun je als volgt coderen:
student_code <- 'x <- c(4, 5)'
testwhat heeft een functie setup_state() die een studenteninzending en een oplossingsscript in gescheiden omgevingen uitvoert en de output en fouten van de studentcode vastlegt. Al deze informatie wordt opgeslagen in de zogenaamde exercise state, die je kunt benaderen met ex():
library(testwhat)
setup_state(stu_code = student_code,
sol_code = solution_code)
ex()
## <RootState>
Deze exercise state kun je doorgeven aan het brede scala aan controlefuncties van testwhat met de piping-syntax uit magrittr. Om te controleren of de student een variabele x heeft gedefinieerd, kun je check_object() gebruiken:
ex() %>% check_object('x')
## <ObjectState>
Deze code draait prima, omdat de student inderdaad een variabele x heeft gedefinieerd. Om verder te gaan en te controleren of de variabele x ook correct is gedefinieerd, kun je check_equal() gebruiken:
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.
Dit resulteert in een fout. check_equal() detecteert dat de waarde van x in de studentenomgeving (een vector) niet overeenkomt met de waarde van x in de oplossing (een enkel getal). Let op hoe de foutmelding een leesbare boodschap bevat die deze fout beschrijft.
Het bovenstaande voorbeeld was interactief: je zet een state op en typt vervolgens ketens van controlefuncties. Op een hoger niveau kun je run_until_fail() gebruiken om de controlecode te omhullen. Dit voert je testbatterij uit totdat er iets faalt:
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."
Deze basisaanpak—een exercise state opbouwen met een studenteninzending en een oplossing en vervolgens run_until_fail() gebruiken om een testbatterij uit te voeren—kan eenvoudig worden ingebed in een autograding-workflow die bij jouw wensen past. Stel dat je studenten hun opdrachten hebben ingeleverd als een R-script dat je hebt gedownload naar de map submissions op je computer (we hebben de map vooraf gevuld met wat willekeurige data). We hebben een reeks R-scripts in de map submissions. Elk R-script bevat een studenteninzending:
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"
We kunnen nu al deze inzendingen doorlopen en een data.frame genereren dat per student aangeeft of de inzending correct was of niet:
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
Deze kleine demo is nog wat ruw, maar hopelijk maakt hij het punt duidelijk: met wat R-werk om de juiste inputs voor setup_state() te bouwen, kun je alle controlefuncties van testwhat inzetten. De tests die je in run_until_fail() opgeeft, controleren zowel het werk van studenten als dat ze zinvolle feedback genereren die hen op hun fouten wijst.
Wil je meer weten over testwhat? Bezoek de GitHub-repo of de packagedocumentatie, gegenereerd met pkgdown. Je vindt er zowel vignetten die laten zien hoe je bepaalde controlefuncties gebruikt, als referentiemateriaal dat alle argumenten beschrijft die je kunt opgeven. Aarzel niet om issues aan te maken op GitHub of contact op te nemen via content-engineering@datacamp.com. We horen graag je feedback! Veel lesplezier!
Deze blog is gegenereerd met RMarkdown. Je vindt de broncode hier.
