Skip to content

Automatische testen

Pieter Janin edited this page May 24, 2024 · 6 revisions

Als er extra checks moeten uitgevoerd worden om een indiening van een student te aanvaarden, kan je als lesgever automatische tests laten lopen wanneer een indiening gemaakt wordt. Deze tests zullen runnen in een Docker container op onze server.

We voorzien hiervoor twee mogelijkheden: tests met de standaard Docker image of met een eigen Docker image.

Welke methode gebruik ik best?

In de standaard image zijn verschillende tools en programma's voorzien. Een lijst daarvan vind je hier. Je uploadt een of meerdere scripts die elke keer uitgevoerd zullen worden in een container van deze image wanneer een indiening gemaakt wordt. We raden aan om deze methode te gebruiken indien mogelijk.

Als je voor het uitvoeren van de testscripts bijkomende programma's nodig hebt, kan je een eigen image laten bouwen op onze server met behulp van een Dockerfile. Gebruik deze methode wanneer de voorziene tools van de standaard image ontoereikend zijn.

Important

Installeer nooit programma's in een testscript. Dit zal namelijk elke keer opnieuw gebeuren wanneer het script wordt uitgevoerd. Installeer nodige tools in de Dockerfile. Een minimaal voorbeeld kan je hier vinden.

Standaard image

Om de standaard image te gebruiken, upload je een of meerdere scripts bij of na het aanmaken van een project. De enige vereiste is dat er een shell script genaamd run aanwezig is. Dit bestand wordt automatisch aangeroepen en dient als entrypoint om eventuele andere testscripts te laten lopen.

Dit kan heel eenvoudig zijn. Om een testscript test.py te runnen, is de inhoud van run gewoon:

#!/bin/sh
python test.py

De standaard image zal de testscripts kopiëren naar de homedirectory van de container. De indiening van de student zal zich bevinden in ~/submission. De structuur van de homedirectory ziet er dan bijvoorbeeld zo uit:

.
├── run
├── submission
│      └── submission.py
└── test.py

Eigen image

Om een eigen image te bouwen, volstaat het om een bestand genaamd Dockerfile te uploaden samen met de testscripts. Een image zal op de server gebouwd worden met een commando ruwweg equivalent aan:

docker build .

waarbij alle geüploade bestanden zich in . bevinden.

Programming interface

Omgevingsvariabelen

Bij het uivoeren van de tests kan je de volgende omgevingsvariabelen gebruiken:

  • $CORRECT: Een pad naar het tekstbestand voor geslaagde testresultaten.
  • $FAILED: Een pad naar het tekstbestand voor gefaalde testresultaten.
  • $EXIT_TEST_FAILED: Een unieke exit code die je gebruikt om aan te geven dat de tests mislukt zijn.
  • $ARTIFACT_DIR: De directory waar gegenereerde artifacts naartoe kunnen geschreven worden als ze beschikbaar moeten gesteld worden na afloop van de automatische tests.
  • $SUBMISSION_DIR: De directory waar de indiening van de student geïnstalleerd wordt. Bij de standaard image wordt deze directory automatisch gekopiëerd naar de homedirectory.

Feedback geven

Je kan aangeven dat een test geslaagd is door een lijn te schrijven naar het bestand $CORRECT, en dat een test niet geslaagd is door een lijn te schrijven naar $FAILED. De inhoud van deze bestanden wordt na het uivoeren van de container uitgelezen en opgeslagen in onze databank. Deze bestanden hebben geen invloed op de status van de indiening.

Deze bestanden gebruik je bijvoorbeeld zo:

# run first test...
echo "First test failed" >> "$FAILED"
# run second test...
echo "Second test succeeded" >> "$CORRECT"

of in python:

import os

with open(os.environ['CORRECT'], 'w') as correct:
    # run first test...
    correct.write("First test succeeded\n")

Important

Testresultaten worden gescheiden door newlines, vergeet ze niet.

De uiteindelijke status van een indiening hangt enkel af van de exit code van de container. Bij een exit 0 wordt de indiening aanvaard. Een exit $EXIT_TEST_FAILED geeft aan dat de indiening geweigerd werd. Alle andere exit codes worden geïnterpreteerd als een crash.

Het is dus de verantwoordelijkheid van de lesgever om te programmeren welke voorwaarden moeten voldaan zijn om een indiening te accepteren.

Artifacten

Bestanden die naar $ARTIFACT_DIR geschreven worden, worden na afloop van de container beschikbaar gesteld voor studenten en lesgevers om te downloaden.

Warning

Artifacten worden gegenereerd en opgeslagen op de server. De nodige backend endpoints zijn ook voorzien, maar zijn nog niet beschikbaar in de webapplicatie. Het is dus niet mogelijk om gegenereerde artifacten op te vragen via de frontend.

Zipbestanden

We raden aan om testscripts in een zipbestand te uploaden. Elk zipbestand wordt meteen automatisch uitgepakt.

Eventuele zipbestanden die ingediend worden door studenten worden niet uitgepakt. Het is de verantwoordelijkheid van de lesgever om ze uit te pakken in de Docker container.

Voorbeelden

Standaard image

Een voorbeeld waarbij de lesgever een testscript in python uploadt.

# run
#!/bin/sh
python test.py

Dit script gaat ervan uit dat de student een bestand submission.py indient.

# test.py
import os

from submission.submission import questionable_code

correct_path = os.environ['CORRECT']
failed_path = os.environ['FAILED']
failed = False

with open(correct_path, 'w') as correct, open(failed_path, 'w') as failed:
    result = questionable_code()

    if is_correct(result):
        correct.write("Test succeeded.\n")
    else:
        failed.write("Test failed.\n")
        failed = True

if failed:
    exit(int(os.environ['EXIT_TEST_FAILED']))

Eigen image

In dit voorbeeld uploadt een lesgever tests met de volgende structuur:

.
├── Dockerfile
├── entrypoint
├── tests
│      └── test1.py
│      └── test2.py
│      └── ...
└── test.py
# Dockerfile
FROM python:3

WORKDIR /home/runner

# copy test scripts to docker image
COPY entrypoint test.py ./
COPY tests/ ./tests
# ...

RUN useradd -m runner
RUN chown -R runner:runner /home/runner/
RUN chmod +x ./entrypoint

# install unavailable python module
RUN pip install --no-cache-dir --upgrade obscure_python_module

ENTRYPOINT ["./entrypoint"]
# entrypoint
#!/bin/sh
cp -R "$SUBMISSION_DIR" "$PWD"
chmod a+wx "$ARTIFACT_DIR"
chmod a+wx "$CORRECT"
chmod a+wx "$FAILED"
su runner -c 'python test.py'
# test.py
...