Moodle. Системы тестирования программ обучающихся
Существенную помощь в организации самостоятельной работы в рамках обучения программированию может оказать использование специальных программных средств, позволяющих в автоматическом режиме проверять корректность разработанной программы. Подобный функционал возможно реализовать на одной из следующих площадках или с использование свободного программного обеспечения:
- Соревнования Уральского федерального университета
- Технокубок от компании mail.ru
- Красноярская школа программиста
- Соревнования по программированию 2.0 (Codeforces)
- Contester 2.4
- Яндекс Контест
- Dudge
- PCMS2
- DOMjudge
- Система Московского центра непрерывного математического образования
Данные системы является самодостаточными и разворачивается на сервере или с ними можно работать зарегистрировавшись в системе. Работа с системой как со стороны администратора, так и со стороны пользователей, в роли которых выступают обучающиеся и преподаватели, осуществляется через веб-интерфейсы. Такая технология обеспечивает дополнительные возможности в организации обучения. Обучаемый может работать с системой из любой точки мира, в которой обеспечен доступ к сети Интернет, и в то же время все действия обучаемого фиксируются на сервере и доступны для преподавателя.
Однако для данных систем есть несколько ограничений и проблем в использовании:
- Дополнительная регистрация
- Отслеживание выполнения
- Оценивание
- Сервер недоступен или медленно проверяет из-за большого количества участников
Среди множества дополнений moodle есть два модуля, схожих по функционалу, а в некоторых моментах и превосходящие указанные выше системы. Первый является полноценным этапом курса с возможностью тонкой настройки и проверки и называется «Virtual Programming lab for Moodle» (сокращенно VPL). Второй является тестовым заданием и может быть включен в состав тестов и называется CodeRunner. Данные дополнения moodle позволяют использовать функционал вышеописанных систем без связанных с ними проблем.
В первую очередь данные дополнения ориентированы на изучение программирования, на работу с классом и использования как автоматически создаваемых, так и настраиваемых вариантов задач, в отличие от тестирующих систем предназначенных прежде всего для проведения олимпиадных соревнований по информатике.
Virtual Programming lab for Moodle
Virtual Programming Lab — это модуль учебного курса moodle, который позволяет создавать и проверять задания на программирование и имеет следующие характерные особенности:
- Редактирование исходного кода программы в браузере с подсветкой кода;
- Запуск интерактивных программ в браузере;
- Тестирование готовых программ;
- Позволяет искать сходство между файлами учащихся;
- Позволяет установить ограничения редактирования, и избежать вставки внешнего текста.
Данный модуль используется для тестирования программ среднего уровня, а также при обучении работы с черепашкой Python.
Метод проверки правильности представленной программы в системе достаточно простой. Создается система тестов, каждый из которых содержит входные данные и выходные данные, которые должны быть выданы правильно работающей программой. Обучаемый через веб-интерфейс пишет текст программы. Программа компилируется на сервере и запускается на выполнение с входными данными, представленными в каждом из тестов. Выходные данные сравниваются с эталоном с помощью специальной подпрограммы, называемой чекером. В системе реализованы компиляторы для подавляющего большинства популярных в настоящее время языков программирования — Ada, Bash script, C, C++, Fortran, Java, Pascal, Prolog, SQL, Scheme, Python и т. д.
Есть возможность установки ограничений на время исполнения и используемую память. Есть возможность создания заданий с несколькими вариантами, а также настройки позволяющие открывать или скрывать от учеников входные и выходные данные тестовых заданий на валидацию программы учащегося с эталонной. Проверка работоспособности программы учащегося возможна в браузере. Это достаточно компактная IDE работающая на любом компьютере с выходом в интернет.
Пример из практики
Условие Задачи 1
В файле files.csv
записаны сведения о файлах. Всего в списке 280 записей, каждая из которых содержит
- имя файла;
- размер файла в Кбайтах;
- тип файла (аудио, видео, изображение, презентация, текстовый, электронная таблица);
- дату создания файла;
- дату последнего изменения файла;
- и уровень доступа.
Все элементы в каждой строке разделены запятыми.
Напишите программу, которая читает данные из файла в массив структур (записей) и выводит на экран
а) количество файлов каждого типа;
б) список 10 самых больших файлов, отсортированный по именам файлов (для каждого вывести имя файла и размер);
в) список презентаций ограниченного доступа, которые изменялись в 2012 году; список нужно отсортировать в алфавитном порядке по именам файлов;
г) список видео размером больше 100 Мбайт, созданных во второй половине 2011 года; список нужно отсортировать по убыванию размеров файлов.
Файл files прикреплен к заданию, но учащийся его не видит.
Проверка производится с помощью специальной программы:
import os
from subprocess import Popen, PIPE
checkGrade = 0
answerData = {}
answer = {"а:":"20 23 83 31 94 29",
"б:":"addition.avi 872791 earthquake.avi 394928 flesh.avi 657246 garden.avi 585151 head.avi 687945 kitten.avi 877704 quartz.avi 439667 rhythm.avi 314300 route.avi 338731 stem.avi 865410",
"в:":"eyes.ppt fall.ppt good-bye.ppt month.ppt rod.ppt tray.ppt",
"г:":"kitten.avi route.avi rhythm.avi face.avi"
}
def comment(s):
#s=s.decode('utf-8')
'''formats strings to create VPL comments'''
if len(s.split("\n"))>2:
for d in s.split("\n"):
print('Comment :=>> ' + str(d))
else:
print('Comment :=>> ' + str(s))
def grade(num):
'''formats a number to create a VPL grade'''
print('Grade :=>> ' + str(num))
with Popen('python3 main.py', shell=True, stdout=PIPE,stderr=PIPE) as proc:
res=proc.communicate()
if proc.returncode:
comment(res[1])
else:
for d in res[0].decode('utf-8').strip().split("\n"):
listD = d.split()
ans = " ".join(listD[1:])
key = listD[0]
answerData[key] = ans
for key in answerData:
if key in answer:
if answer[key].replace(' ','') == answerData[key].strip().replace(' ',''):
checkGrade += 1
print('Comment :=>> ' + 'Выполнено задание '+key)
moodle_max_grade = float(os.environ["VPL_GRADEMAX"])
check = int(checkGrade/4*100)
print('Comment :=>> ' + "Вы выполнили задание на " + str(check)+ "%")
check = moodle_max_grade*(check/100)
grade(check)
Которая так же не видна учащимся.
Условие Задачи 2.
В одной фирме решили организовать локальную сеть, но инженер Вася не ходил на лекции по основам организации сети и забыли купить маршрутизатор. Однако его дедушка, знающий военный инженер связист, рассказал ему что 30 лет назад они соединяли все компьютеры в одну сеть используя один кабель. Такая топология сети называлась «Шина». Вася решил организовать сеть по топологии Шина, а для этого ему нужно проложить как можно меньше кабеля, чтобы уложиться в бюджет и организовать сеть без маршрутизатора. Помогите Васе рассчитать минимальную длину кабеля, которую нужно заказать в магазине.
Проверка производится на основе стандартных средств модуля по параметрам заданным в специальном файле:
ase=#1
grade reduction=100%
input=3 3
1 2 1
2 3 2
3 1 3
output=3
....
Case=#4
grade reduction=100%
input=8 8
1 2 1
2 4 3
4 3 7
3 6 9
5 6 6
6 7 4
7 8 2
8 1 1
output=24
Есть небольшая возможность указывать учащимся варианты, но она достаточно простая и требует дополнительно описывать программу теста. Вариант теста храниться в глобальной переменной VPL_VARIATION0
CodeRunner
CodeRunner — это бесплатный модуль с открытым исходным кодом для Moodle, который может запускать программный код на разных языках программирования, представленный учащимися в качестве ответа. Он предназначен главным образом для использования в курсах компьютерного программирования, хотя он может использоваться для оценки любого вопроса, ответ на который является текстом. Обычно используется в адаптивном режиме тестов Moodle; учащиеся пишут свой код на каждый вопрос по программированию и сразу же получают результаты тестирования кода. Затем они могут исправить свой код и отправить повторно, как правило, с небольшим штрафом в 10% и есть возможность установки этого значения.
Тестовые задания помеченные светло-зеленым цветом не видны учащемуся.
В настоящее время поддерживает Python2, Python3, C, C++, Java, PHP, JavaScript (NodeJS), Octave и Matlab. Архитектура позволяет добавлять и другие языки программирования, например Pascal.
Данная система уже используется во множестве зарубежных учебных учреждениях, а также в школе 179 г. Москвы и Инженерный лицей НГТУ в г. Санкт Петербург.
Тонкая настройка вопроса позволяет запретить использовать некоторые встроенные функции языка программирования или проверять только определенные функции или процедуры написанные учащимся.
Важной особенностью модуля CodeRunner является возможность встраивать его в тестовое задание как один из вопросов теста, что значительно повышает возможности формирования алгоритмического мышления учащихся.
Тип вопросов CodeRunner поддерживает возможность генерации мультивариантных вопросы для каждого учащегося путем использования механизмов шаблона Twig.
Пример из практики
Условие Задачи 1.
Условие задачи задано шаблоном Twig:
На вход программы поступает неизвестное количество целых чисел, ввод заканчивается нулём. Требуется написать программу, которая подсчитает кол-во чисел оканчивающихся на {{ dN }}
Параметры Twig:
{
{% set index = random(2) %}
"text": "{{ ["двухзначных","трехзначных","четырехзначных"][index] }}",
"uravnen": "{{ ["9<n<100","99<n<1000","999<n<10000"][index] }}",
"nRange1": "{{ ["1","50","800"][index] }}",
"nRange2": "{{ ["200","300","3000"][index] }}",
"dN": "{{ 3 + random(6) }}"
}
Программа проверки решения:
import subprocess
import random
import json
random.seed()
student_ans = """{{ STUDENT_ANSWER | e('py') }}"""
test_program = """{{ QUESTION.answer | e('py') }}"""
def someStreamCreatingProcess(stream1, stream2):
for i in range(200):
x = str(random.randint({{ nRange1 }}, {{ nRange2 }}))+"\n"
stream1.write(bytes(x, encoding='utf-8'))
stream2.write(bytes(x, encoding='utf-8'))
stream1.write(bytes("0\n", encoding='utf-8'))
stream2.write(bytes("0\n", encoding='utf-8'))
stream1.close()
stream2.close()
with open('student.py', 'w') as fout:
fout.write(student_ans)
with open('test.py', 'w') as fout:
fout.write(test_program)
subpr1 = subprocess.Popen(["python3", "student.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
subpr2 = subprocess.Popen(["python3", "test.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
someStreamCreatingProcess(stream1=subpr1.stdin, stream2=subpr2.stdin)
chek = subpr1.wait()
err = subpr1.stderr.read()
out1 = subpr1.stdout.read()
out2 = subpr2.stdout.read()
if err:
mark = 0
result = {'got': str(err.strip().decode()), 'fraction': mark}
else:
if out1 == out2:
mark = 1
great = "Супер! У тебя все получилось"
result = {'got': great, 'fraction': mark}
else:
mark = 0
result = {'got': str(out1.strip().decode()), 'expected': str(out2.strip().decode()), 'fraction': mark}
print(json.dumps(result))
Эталонная программа:
n = int(input())
g = 0
while n != 0:
if {{ uravnen }} and n%10 == {{ dN }}:
g = g+1
n = int(input())
print(g)
Условие Задачи 2.
Известно что список a содержит только целочисленные элементы, количество этих элементов неизвестно. Необходимо написать программу, которая в заданном списке найдет максимальный по значению элемент.
Программа проверки решения:
# -*- coding: utf-8 -*-
__saved_input__ = input
def input(prompt=''):
s = __saved_input__(prompt)
print(s)
return s
import sys
import codecs
sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())
__student_answer__ = """{{ STUDENT_ANSWER | e('py') }}"""
if "max(" not in __student_answer__.replace(' ', ''):
pass
else:
print("Запрещено использовать функцию max")
sys.exit(0)
SEPARATOR = "#<ab@17943918#@>#"
{% for TEST in TESTCASES %}
{{ TEST.extra }}
{{ TEST.testcode }}
{{ STUDENT_ANSWER }}
{% if not loop.last %}
print(SEPARATOR)
{% endif %}
{% endfor %}
В данном случае проверка производится путем запуска программы учащегося на нескольких тестовых значениях. Результат программы учащегося сравнивается с эталонным:
Вишенка на торте для инженерных классов. Arduino и CodeRunner.
Возможности Moodle и модуля CodeRunner позволяют также внедрить мини курс по изучению микроконтроллеров на базе платформы Arduino.
Тонкая настройка вопроса позволила описать стандартные функции и операторы Arduino IDE и импортировать их перед запуском программы учащегося. Сопоставление производится путем простого алгоритма, в котором сравниваются данные полученные на эталонном алгоритме и алгоритме учащегося.
В данном примере в вопрос встроена виртуальная плата Arduino с сайта Tincercad, на которой можно испытать свой код даже без наличия реальной платы на руках.
Ответ учащийся заносит в поле ответа, проверка так же автоматическая, как и в случае с задачами на программирование.
Полная документация на английском языке для описанных выше модулей находится тут Coderunner и тут VPL