Valide_digitaal_toetsen

In deze situatie van de Corona crisis en leerlingen die van huis uit schoolwerk doen, zoeken veel docenten naar valide manieren om leerlingen te toetsen. Zeker naarmate deze thuiswerk situatie langer duurt, zal dit noodzakelijk zijn om de voortgang van de leerlingen te meten. Leerlingen zullen echter geneigd zijn om elkaar te gaan ‘helpen’ tijdens de toets, waardoor de toets niet echt een goede meting oplevert. Een mogelijke oplossing is, om voor iedere leerling automatisch een andere versie van de toets te maken. Zo is het niet mogelijk om antwoorden met elkaar te delen.

Let wel, deze manier van toetsen werkt vooral bij vakken, waarbij de antwoorden berekend, bedacht of samengesteld moeten worden en niet zo vanuit het boek gehaald kunnen worden.

HandiHow heeft geëxperimenteerd met een mogelijke oplossing binnen Google formulieren. Dit is populair bij veel scholen, omdat er een Google omgeving wordt gebruikt, en toetsen in de vorm van een Google formulier kunnen worden uitgezet via Google Classroom.

Tutorial: digitale toetsen in Google formulieren

Let op! Enige programmeerkennis van Javascript is vereist om deze tutorial te kunnen volgen. Het kost wel wat tijd, maar uiteindelijk heb je weinig nakijkwerk, want de antwoorden worden automatisch gecheckt in het Google formulier. Dus het is wellicht de moeite waard om dit te doen. Ook omdat je de toets jarenlang kan gebruiken. Bovendien is het zo dat als je eenmaal een goed script voor jouw sectie hebt, je daarna door alleen de vragen aan te passen voor elk onderwerp of leerjaar snel een nieuwe toets maakt. Je kunt het dus steeds weer opnieuw toepassen.

De strategie is als volgt:

  • We maken eerst een formulier die algemene informatie van de leerlingen verzamelt
  • We kunnen email adressen automatisch verzamelen en ook instellen dat dit formulier per leerling maar 1 keer ingediend mag worden
  • Het indienen van dit formulier leidt tot het draaien van een automatisch script
  • In dit script wordt een Google quiz gemaakt, specifiek voor de betreffende leerling. De link naar deze quiz wordt per e-mail naar de leerling verzonden
  • De leerling krijgt dus automatisch zijn eigen versie van de toets en kan deze vervolgens gaan maken en indienen
  • De docent kan in zijn Google Drive alle formulieren vinden, waarbij de naam en de klas van de leerling als bestandsnaam vermeld staan

Voordelen:

  • Iedere leerling krijgt een eigen versie van de toets, dus is er geen mogelijkheid om antwoorden te delen
  • Er worden automatisch zeer veel foute antwoorden gemaakt, dus gokken op een antwoord levert een laag cijfer op
  • Het werk wordt automatisch nagekeken dus er is geen nakijkwerk

Nadelen:

  • Iedere leerling heeft een eigen formulier dus krijg je geen overzicht van de klas
  • De formulieren moeten naderhand handmatig worden nagelopen om het overzicht te maken van alle cijfers

Stap 1. Maak het inschrijfformulier

We maken eerst een inschrijfformulier (Google Form). We stellen in dat email adressen worden verzameld en dat respondenten slechts 1 antwoord mogen indienen (anders kan de leerling meerdere toetsen opvragen).

We stellen bij “Presentatie” het volgende bevestigingsbericht in:

“Bedankt voor je inschrijving. Je krijgt de link naar de toets per email toegestuurd.” is.

We maken nu een aantal verplichte velden in het formulier:

  • Email (dit veld maakt Google Forms automatisch als je “Email-adressen verzamelen” instelt)
  • Naam – soort vraag is korte antwoord tekst – stel in op verplicht
  • Klas – soort vraag is multiple choice – stel in op verplicht – opties zijn bijv. “3A”, “3B”, “3C”

Stap 2. Open de spreadsheet die bij het inschrijfformulier hoort

Ga nu naar het tabblad “Antwoorden” en klik rechtsboven op het icon van Google Sheets.

Maak een nieuwe spreadsheet. De naam is automatisch ingevuld.

Je opent nu de spreadsheet door te klikken op “Maken”.

Je gaat nu naar het menu “Extra” en klikt dan op “Scripteditor”.

We gaan nu werken aan een script dat automatisch wordt gedraaid, telkens als een leerling zich heeft ingeschreven voor de toets.

Dit script is ervoor verantwoordelijk dat er een nieuw Google formulier wordt gemaakt, met de specifieke versie van deze toets voor deze leerling.

Voor het maken van dit script is kennis nodig van Javascript.

We maken nu een functie die de formulieren bewerkt.

Stap 3. De hulpbronnen en trigger van het script instellen

We bewaren eerst het project onder zijn eigen naam.

We noemen dit project “Toets versie emailen naar leerling”.

function onFormSubmit(e) {
  //get the variables from the inital form submission
  var values = e.namedValues;
  var email = values['E-mailadres'];
  var name = values['Naam'];
  var classroom = values['Klas'];
  
  Logger.log(values);
}

We hernoemen de functie “myFunction” en noemen deze functie nu “onFormSubmit(e)”.

Uit de variabele “e” kunnen we de informatie halen van het ingediende formulier.

We krijgen zo het email adres, de naam en de klas van de leerling. Je kunt de logger zien door Cmd + Enter te klikken.

Stel nu “Hulpbronnen” in en ga naar “Geavanceerde Google-services”.

Je vinkt de opties aan voor “Drive API” en “Gmail API”.

Ga naar het menu “Bewerken” en klik op “Triggers voor je huidige project”.

Er is ook een klein icoontje met een klok. Zo kun je er ook direct naartoe.

Stel in dat je de functie “onFormSubmit” wilt uitvoeren met de afspraakbron “Uit spreadsheet” en het gebeurtenistype “Bij verzenden formulier”.

Stel in dat je direct een melding krijgt als de functie uitvoering mislukt. Zo kun je snel reageren als een leerling de toets niet krijgt (bij fout in de verwerking).

Je kunt nu eerst uitproberen of de trigger succesvol is ingesteld. Je vult het inschrijfformulier in en opent daarna de logger.

Als het goed is, krijg je geen email met foutmeldingen, en zie je in de logger het email adres, de naam en de klas die je zojuist hebt ingevuld. Nu kunnen we verder met het maken van de toets.

Stap 4. Automatisch een nieuwe versie maken van de toets

We maken nu een functie die de quiz maakt. Als input van deze functie hebben we de naam en de klas van de leerling. Zo kunnen we het formulier bewaren met de bestandsnaam inclusief naam en klas. Dit gebeurt op na de comment “create the form”.

Daarna stellen we het formulier in op Quiz. We definiëren een aantal random variabelen. Ook maken we arrays met de juiste eenheid en daarna nog twee foute eenheden. De variabelen en de lijsten met eenheden gaan we gebruiken om het juiste antwoord uit te rekenen, maar ook om een groot aantal foute antwoorden te genereren met soms ook onjuiste eenheden.

We maken ook een array met vragen, waarin we een aantal settings definiëren zoals de titel van de vraag, de berekening van het juiste antwoord, de eenheden array die van toepassing is op dit antwoord, het aantal punten dat de vraag oplevert, en het aantal foute antwoorden dat automatisch moet worden gemaakt bij de vraag.

Als laatste zetten we in het return statement dat de functie de “publishedUrl” string moet teruggeven. Dit gaan we daarna e-mailen naar de leerling.

function createForm(name, classroom) {
  //create the form
  var form = FormApp.create('Toets remmen en botsen - ' + name + ' - ' + classroom);
  
  form
  .setIsQuiz(true)
  .setLimitOneResponsePerUser(true)
  .setCollectEmail(true)
  .setRequireLogin(true)
  .setPublishingSummary(true);
  
  //create random initialization variables
  var massCar = getRandomInt(1000, 2500); //mass in kg
  var massDriver = getRandomInt(60, 100); //mass in kg
  var speedCar = getRandomInt(20, 40); //speed in m/s
  var breakingTime = getRandomInt(4, 8); //time it takes to stop the car in s
  var breakingForceCar = getRandomInt(2500,5000); //breaking force in Newton
  var reactionTime = getRandomInt(5,10) / 10; //reaction time in seconds
  var crashingTime = getRandomInt(10,20) / 100; //crashing time in seconds
  
  //create arrays with the correct unit of measure in the first element and some wrong units in the second and third element
  var accelerationUnits = ['m/s2', 'm/s', 'm'];
  var velocityUnits = ['m/s', 'm/s2', 'm'];
  var forceUnits = ['N', 'Pa', 'm/s'];
  var locationUnits = ['m', '', 'm/s'];
  var timeUnits = ['s', 'm', 'm/s']
  
  //create all questions
  var questions = [
    {
      question: 'Een auto rijdt met een snelheid van ' + speedCar + ' m/s. De auto stopt in ' + breakingTime + ' seconden. Bereken de vertraging van de auto.',
      answer: speedCar / breakingTime,
      unitArray: accelerationUnits,
      points: 3,
      wrongAnswers: 9
    },
    {
      question: 'De auto heeft een massa van ' + massCar + ' kg. Bereken de remkracht op de auto terwijl de auto stopt. Gebruik dezelfde gegevens uit de vorige opgave hiervoor.',
      answer: speedCar / breakingTime * massCar,
      unitArray: forceUnits,
      points: 2,
      wrongAnswers: 9
    },
    {
      question: 'Bereken de stopafstand van de auto. Gebruik weer dezelfde gegevens uit opgave 1 hiervoor.',
      answer: speedCar / 2 * breakingTime,
      unitArray: locationUnits,
      points: 2,
      wrongAnswers: 9
    },
    {
      question: 'De auto gaat weer optrekken. Zijn snelheid is daarna wederom ' + speedCar + 
      ' m/s. Dan ziet de bestuurder een konijn. Zijn reactietijd is ' + reactionTime + ' seconde. Bereken de reactie-afstand.',
      answer: speedCar * reactionTime,
      unitArray: locationUnits,
      points: 2,
      wrongAnswers: 9
    },
    {
      question: 'Het konijn kwam de weg op toen hij nog een afstand had van 150 meter van de auto. ' + 
      ' Bereken hoe snel de auto moet afremmen - na de reactietijd - om tot stilstand te komen en het konijn net niet plat te rijden',
      answer: (150 - speedCar * reactionTime) / speedCar / 2 ,
      unitArray: timeUnits,
      points: 4,
      wrongAnswers: 9
    },
    {
      question: 'Het is gelukkig goed afgelopen met het konijn. Hij kon op tijd van de weg springen. De auto trekt weer op en heeft ' + 
      'dan weer een snelheid van ' + speedCar + ' m/s. Na een tijdje krijgt de auto een klapband en botst hij tegen een boom. ' +
      'Door de kreukelzone vertraagt de auto eenparig en staat hij na ' + crashingTime + ' seconde stil. Bereken de vertraging. ',
      answer: speedCar / crashingTime,
      unitArray: accelerationUnits,
      points: 3,
      wrongAnswers: 9
    },
    {
      question: 'De bestuurder van de auto heeft een massa van ' + massDriver + ' kg. Bereken de kracht op de veiligheidsgordel van de bestuurder tijdens de botsing.',
      answer: speedCar / crashingTime * massDriver,
      unitArray: forceUnits,
      points: 2,
      wrongAnswers: 9
    }
  ];
  questions.forEach(question => {
     createMultipleChoiceItem(form, question.question, question.answer, question.unitArray, question.points, question.wrongAnswers);
  })
  
  return form.getPublishedUrl();
}

We definiëren de functie die een multiple choice vraag maakt.

function createMultipleChoiceItem(form, title, correctAnswer, unitArray, points, numberOfWrongChoices){
  var item = form.addMultipleChoiceItem();
  //generate all the question choices
  var correctAnswerString = roundOneDecimal(correctAnswer).toString() + ' ' + unitArray[0];
  var choices = [item.createChoice(correctAnswerString, true)]
  for (let step = 0; step < numberOfWrongChoices; step++) {
    choices.push(item.createChoice(generateRandomWrongChoiceString(correctAnswer, unitArray), false))
  }
  //now set all properties on the question
  item
  .setTitle(title)
  .setChoices(choices.sort(() => Math.random() - 0.5))
  .setPoints(points)
  .setFeedbackForCorrect(FormApp.createFeedback()
                         .setText('Dit is het juiste antwoord! Goed gedaan.').build())
  .setFeedbackForIncorrect(FormApp.createFeedback()
                         .setText('Dit is niet het goede antwoord. Het juiste antwoord is ' + correctAnswerString).build())
  .showOtherOption(false)
  .setRequired(true);
  
}

En daarbij nog een paar helper functies.

function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function roundOneDecimal(number) {
  return Math.round(number * 10) / 10
}

function generateRandomWrongChoiceString(correctAnswer, unitArray){
  return roundOneDecimal(correctAnswer * Math.random())  + ' ' + unitArray[getRandomInt(0,2)]
}

Stap 5. Aanpassen van de onFormSubmit functie

We moeten nu nog de “onFormSubmit” functie aanpassen, zodat deze functie steeds een nieuwe versie van de toets maakt en de link per email verstuurd naar de leerling. Hiervoor gebruiken we de “createForm” functie die we eerder hebben gemaakt. We construeren een HTML body voor de email met deze link erin.

GmailApp.sendEmail(…) kan daarna worden gebruikt om de email te versturen. Zie de aangepaste functie hieronder.

function onFormSubmit(e) {
  //get the variables from the inital form submission
  var values = e.namedValues;
  var email = values['E-mailadres'];
  var name = values['Naam'];
  var classroom = values['Klas'];
  
  Logger.log(values);
  //create the quiz in Google Forms and get the published Url
  var publishedUrl = createForm(name,classroom);
  
  //construct the email to the student
  var htmlBody = '<p>Beste ' + name + '</p>';
  htmlBody += '<p>Je kunt jouw toets nu beginnen door op de onderstaande link te klikken. Veel succes!</p>';
  htmlBody += "<a href=\"" + publishedUrl + "\">Link naar jouw persoonlijke test</a>";

  GmailApp.sendEmail(email, 'Toets remmen en botsen', '', {htmlBody: htmlBody})
  
}

Controleer nu of alles goed gaat! Vul nog een keer het inschrijfformulier in en doe de quiz. Kijk ook of je de toets weer terug kunt vinden in je Google Drive!

Veel succes met toetsen.

Heb je vragen hierover of heb je hulp nodig bij het maken van zulke digitale toetsen? Kom dat gerust in contact met HandiHow.