Компьютерные инструменты в образовании, 2014 № 5: 50-58 УДК: 004.415.28 http://ipo.spb.ru/journal
СИСТЕМЫ ТЕСТИРОВАНИЯ
Денисов Денис Валерьевич Аннотация
Современные реалии требуют уделять особое внимание подготовке высококлассных программистов. В числе наиболее эффективных способов такой подготовки находятся олимпиады по программированию и специальные курсы дистанционного обучения. К автоматизированным системам, обслуживающим подобные мероприятия, предъявляются достаточно жесткие требования к производительности, стабильности и безопасности работы. В работе приведен обзор архитектуры наиболее известных тестирующих систем, проанализированы их достоинства и недостатки и предложена архитектура системы, разработанная с учетом этих недостатков. На основе предложенной архитектуры разработана система, опыт внедрения которой также приводится в статье.
Ключевые слова: тестирование программ, олимпиады по программированию.
ВВЕДЕНИЕ
Различные соревнования по программированию, такие как ACM ICPC [1], играют важнейшую роль в подготовке современных программистов. В процессе участия в соревнованиях повышаются знания фундаментальных алгоритмов и структур данных, навыки тестирования кода и работы в команде, умение быстро и правильно решать поставленную задачу. Обслуживать любое соревнование по программированию может автоматическая система тестирования программ. Такая система должна обеспечивать организаторов и участников определенной функциональностью, позволяющей следить за активностью участников, тестировать присылаемые ими решения в соответствии с определенными заранее правилами, информировать участников о результатах тестирования, определять победителя по тем или иным критериям, предоставляя единую среду взаимодействия.
Существующие тестирующие системы обладают рядом недостатков, ограничивающих их применение. К таким недостаткам относятся ограниченная продолжительность соревнования, отсутствие поддержки игровых задач, невозможность выдачи разных заданий разным участникам, трудоёмкость добавления новой функциональности к системе и интеграции с другими информационными системами.
В данной работе представлена архитектура тестирующей системы, в которой устранены многие из этих недостатков, приводится её сравнение с существующими аналогами и описан опыт практического внедрения разработанной системы.
© Денисов Д.В., 2014
БАЗОВАЯ ТЕРМИНОЛОГИЯ
В этом разделе дается пояснение специальных терминов, необходимых для дальнейшей работы.
Участники соревнований по программированию получают набор задач, для каждой из которых на специальном сервере хранится набор тестовых данных (возможно, с дополнительными программами, проверяющими ответ участника). Участники должны писать программы, решающие эти задачи, после чего отсылать их на сервер, где они компилируются и проверяются на имеющемся наборе тестовых данных.
Тестом назовем набор данных, инструкций и правил их применения, используемый для проверки корректности решения задачи.
Программа, являющаяся правильным решением той или иной задачи, должна пройти все тесты, выдав для каждого из них правильный ответ. В условиях каждой задачи определены ограничения по времени работы программы и по объему используемой ею оперативной памяти. Превышать эти ограничения на используемые ресурсы нельзя.
Будем говорить, что программа проходит тест, если при ее запуске согласно правилам, которые определены в тесте, программа успешно завершается, не превысив ограничений на ресурсы, а также выдает корректный ответ. Корректность ответа проверяет другая специальная программа — чекер (англ. checker), сравнивая эталонное решение жюри с решением, которое выдает программа участника.
Тестированием программы назовем процесс ее запуска на предложенных жюри тестах, с целью установления того, что программа проходит тесты, либо того, что она их не проходит.
Перетестированием назовем процесс повторного тестирования при изменении тестов.
Итак, задача по программированию состоит не только из условий, которые получают участники (в бумажном или электронном виде), в нее также входит множество тестов и специальная программа-чекер проверки ответов на корректность. Совокупность этих элементов будем называть классической задачей. Существует несколько видов классических задач.
• Пакетные. Отправленная участником программа запускается на всех тестах, а специальная программа-чекер проверяет полученные ответы.
• Интерактивные. Программа участника взаимодействует со специальной программой — интерактором (англ. interactor), подготовленной жюри. Интерактивные задачи расширяют круг возможных задач, поскольку программа-интерактор может модифицировать тестовые данные в зависимости от того, что выводит участник.
• Задачи только с выводом. Участникам сразу предоставляется набор входных данных, а они отправляют на проверку только ответы к этим данным.
Подготовить правильный набор тестов для каждой классической задачи непросто, поскольку нужно учесть все граничные случаи, а также иметь в виду некорректные решения, работающие на большинстве стандартных тестовых данных.
Решением задачи назовем программу, написанную на каком-либо языке программирования, про которую заявлено, что она решает данную задачу. Такое понятие решения позволяет вводить так называемые частичные решения — решения данной задачи при строгих ограничениях, и приближенные решения — решения, выдающие ответ, в каком-то смысле близкий к правильному.
Помимо классической задачи существует задача игровая, в которой целью является не прохождение множества тестов, а победа одной программы над другой. Игровой задачей будем называть совокупность условия задачи (в бумажном, электронном или устном виде) и правил взаимодействия программ-участников друг с другом. Игровые задачи предполагают реализацию стратегии действий в некоторой игре. Под правилами взаимодействия уча-
стников друг с другом мы подразумеваем правила игры, а не технические аспекты реализации игры по этим правилам, которые остаются на усмотрение участников.
Процесс взаимодействия двух игровых программ-участников называется партией. Партия контролируется специальной программой, регулирующей правила взаимодействия программ-участников и управляющей очередностью ходов. По результатам партий определяется оценка участника.
Тестированием игровой задачи будем называть процесс организации взаимодействия между программами участников и оценивания решений участников по результатам этого взаимодействия.
Контестом назовем множество задач и способ оценивания решений этих задач. Такое определение позволяет нам единообразно рассматривать как соревнования по программированию, так и университетские курсы, связанные с программированием и организованные по принципу марафонского соревнования продолжительностью в 1 учебный семестр или целый год.
Турниром стратегий будем называть контест, в котором все задачи являются игровыми. Отметим, что контесты подобного рода сочетают в себе как серьезное программирование -элементы искусственного интеллекта, жесткие ограничения по времени расчета очередного хода — так и развлекательный элемент: наблюдать за процессом игры весьма увлекательно. Это позволяет увлечь программированием большее количество людей.
Автоматизированной проверяющей системой (тестирующей системой, в дальнейшем — просто системой) назовем комплекс программных средств, позволяющий производить автоматическую проверку и оценивание решений задач по программированию, а также организующих процесс взаимодействия жюри и участников соревнования по программированию.
ПОСТАНОВКА ЗАДАЧИ
Создание тестирующей системы, поддерживающей все мыслимые типы контестов, является неоправданно трудоемким, поэтому ограничимся лишь несколькими типами контестов, наиболее распространенными на практике.
В рамках данной работы рассматривается использование тестирующей системы для проведения личных и командных соревнований по программированию, а также для организации обучения программированию школьников и студентов. В связи с этим, к системе выдвигаются следующие требования:
• Проведение контестов по наиболее распространенным правилам оценивания соревнований по программированию — по правилам ACM и по правилам международной олимпиады школьников IOI. Правила ACM широко используются на студенческих соревнованиях по программированию [2, 3]. Правила IOI, помимо самой олимпиады, используются на различных соревнованиях среди школьников, а также в Летней компьютерной школе [4, 5, 6].
• Поддержка наиболее популярных языков программирования, в особенности, используемых на олимпиадах — Pascal, C, C++, Java, Python, C# — с возможностью расширять множество поддерживаемых языков.
• Автоматическая проверка решений в предположении, что множество тестов представляет собой множество наборов входных и выходных данных и, возможно, программу-чекер, подтверждающую корректность ответа программы участника.
• Автоматический прием решений от участников.
• Наличие интерфейса администратора, позволяющего оперативно вмешиваться в ход контеста: перетестировать решения, дисквалифицировать участников, нарушивших правила и т. д.
• Автоматическая генерация результатов соревнования по результатам проверки решений участников.
• Возможность проведения учебно-тренировочных контестов. От соревнований они, в частности, отличаются неопределенным временем завершения — в таком контесте можно участвовать когда угодно.
• Тестирование игровых задач и, как следствие, возможность организации игровых контестов.
• Распределение процессов тестирования на несколько серверов. Тестирование, особенно игровой задачи, может выполняться очень долго при большом количестве участников.
• Возможность выдавать разным участникам разные задачи (из некоторого набора). Это актуально при проведении учебных курсов.
ОБЗОР НАИБОЛЕЕ РАСПРОСТРАНЕННЫХ ТЕСТИРУЮЩИХ СИСТЕМ
Здесь мы приведем краткий обзор существующих тестирующих систем и отметим их архитектурные и функциональные особенности. Среди них особо отметим TestSys, используемую в Санкт-Петербургском государственном университете [3], и ejudge, широко используемую в Летней компьютерной школе и при проведении Открытого кубка [2]. Помимо указанных систем, существуют и другие, но они менее распространены.
TestSys — автоматизированная тестирующая система, разработанная ведущими тренерами команд СПбГУ по программированию Андреем Лопатиным и Николаем Дуровым. В настоящее время используется в Санкт-Петербургском государственном университете для проведения тренировочных и отборочных соревнований по программированию. Система состоит из нескольких исполняемых модулей, работающих в ОС Windows. Основную работу выполняет главный модуль системы testsys.exe, который хранит информацию обо всех контестах, отправленных решениях, участниках и задачах. Компиляция и тестирование решений осуществляется отдельным модулем judge.exe, который может быть развернут в нескольких экземплярах на различных серверах. Для взаимодействия с пользователем используется Web-интерфейс. В качестве базы данных TestSys использует файлы специфического формата.
TestSys поддерживает оценивание как по правилам ACM, так и по правилам IOI. Для правил IOI введены дополнительные возможности. Например, можно оценивать решения участников друг относительно друга: кто лучше всех решил задачу, получает по ней полный балл.
При всех своих достоинствах, TestSys не подходит для организации учебных курсов, поскольку продолжительность контеста в ней ограничена двумя месяцами, тогда как даже один семестр длится дольше. В настоящий момент система TestSys дорабатывается командой энтузиастов из СПбГУ, однако некоторые возможности встроить в нее не удается в силу архитектурных ограничений.
Также стоит отметить, что основная логика системы сконцентрирована в модуле testsys.exe (а web-интерфейс является лишь тонким клиентом к нему), что затрудняет расширение возможностей системы. Также расширение возможностей ограничивается форматом файлов, в которых система хранит данные о каждом контесте.
Система ejudge разработана в Московском государственном университете тренером команд МГУ Александром Черновым [7]. Используется для проведения четвертьфинала чемпионата мира в Московском подрегионе Северо-Восточного Европейского региона. Также используется в Летней компьютерной школе для проведения Открытого кубка России по программированию, а также на тренировочных серверах Московского государственного университета.
На данный момент ejudge является одной из наиболее мощных тестирующих систем. Она поддерживает, как правило, ACM и IOI, так и некоторые их модификации. В ejudge есть возможность проводить так называемые виртуальные контесты, в которых каждый участник сам определяет для себя время начала, при этом таблица результатов меняется соответствующим образом.
Для взаимодействия с участниками и администраторами ejudge использует web-интер-фейс, для администраторов также предоставляется интерфейс командной строки. Практически действия по администрированию (за исключением загрузки тестов к задачам на сервер и некоторых административных функций) выполняются через него.
Архитектурно ejudge представляет из себя несколько модулей, реализующих основные функции системы, а также два комплекта интерфейсных программ — CGI-программы, реализующие web-интерфейс, и консольные программы, предоставляющие, соответственно интерфейс командной строки. Так же, как и в TestSys, интерфейсные программы являются тонкими клиентами к основному ядру системы. Это затрудняет расширение возможностей системы. Также ejudge не поддерживает игровые задачи и крайне сложен в настройке и управлении.
Обе представленные системы архитектурно можно разделить на основные модули, которые взаимодействуют друг с другом через общую файловую систему и/или базу данных и вспомогательные модули (в основном модули компиляции и тестирования), которые общаются с основной частью системы по сети и могут быть разнесены по нескольким физическим серверам. Такое решение выглядит обоснованным, поскольку элементы каждой задачи удобнее всего хранить непосредственно в файловой системе. Поскольку в большинстве тестирующих систем основные компоненты системы не создают высокой нагрузки на сервер, это не доставляет неудобств. Основную же нагрузку на сервер создает именно процесс тестирования решений, который и может быть вынесен на несколько раздельных серверов.
АРХИТЕКТУРА СИСТЕМЫ
Для обеспечения возможности распределения нагрузки на несколько серверов функциональность системы разделена по нескольким модулям. Тестирование каждого вида задач, особенно игровых, имеет свою специфику, поэтому отдельные модули требуются и для задач каждого вида.
Перечислим основные модули системы, кратко поясняя их назначение и давая им специальное имя.
• Центр управления (fsystemcc). Запускает или останавливает все остальные модули, а также отслеживает их состояние. Аналогичных модулей в других системах нет, в ejudge управление компонентами системы осуществляется штатными средствами ОС, в testsys предполагается ручное управление.
• Диспетчер тестирования (fsystem). Его основное назначение — выборка отосланных решений из базы данных и организация их тестирования. Модуль работает только с задачами пакетного и интерактивного типов. Этот модуль по назначению схож с основными модулями ejudge и testsys, однако значительно упрощен, поскольку вся логика, не связанная непосредственно с тестированием пакетных и интерактивных задач, реализуется другими модулями.
• Диспетчер тестирования игровых задач (fsgt). Модуль предназначен для организации тестирования игровых задач: формирование списка партий по списку отправленных решений, распределение партий по вспомогательным модулям, оценивание решений по результатам сыгранных партий. Поскольку процесс тестирования игровых задач кардинально отличается от процесса тестирования других типов задач, его организация была вынесена в отдельный модуль.
• Модуль управления партией (fsgc). Модуль непосредственно управляет партией: запускает две программы-игрока, проверяющую программу, организовывает взаимодействие между ними, отслеживает использованные ресурсы — время и память.
• Компилирующий модуль (fscompiler). Очевидно назначение модуля — компиляция присланных в систему решений. Модуль работает с задачами любого типа. В testsys компиляцией занимается модуль judge.exe, в ejudge есть отдельный модуль, работающий на сервере.
• Тестирующий модул ь (j udge). Последовательно запускает присланные и успешно скомпилированные решения на имеющихся тестах, отслеживает использованные ресурсы, после завершения работы решения запускает программу-чекер для определения правильности полученного ответа. И в TestSys, и в ejudge эта функциональность также вынесена в отдельный модуль, который может работать на сервере, связанном с основным сервером системы только по сети.
• Модуль тестирования задач только с выводом (fsootest). Предназначен для тестирования задач, условие которых подразумевает отправку участниками готовых ответов. Процесс тестирования таких задач не подразумевает ни запуска программы участника, ни ее компиляции, а только распаковку ответов и запуск программы-чекера с целью определения их правильности. Выполняется непосредственно на сервере тестирования, поскольку не создает высокой нагрузки.
• Web-интерфейс системы. Предназначен для взаимодействия системы с пользователями: как участниками соревнований, так и администраторами. В нем также содержится логика управления правами доступа, формирования результатов контеста, интерфейс для редактирования контестов, задач и прочего. В TestSys и в ejudge Web-интерфейс представляет собой тонкий клиент к основному ядру системы.
Разделение компилирующих и тестирующих модулей необходимо, так как процессы компилирования и тестирования могут выполняться под различными операционными системами. Другая причина такого разделения заключается в удобстве настройки системы: тестирующему модулю не требуется настройка всех доступных компиляторов на сервере, при этом тестирующих модулей обычно требуется больше, чем компилирующих. Этим разработанная система отличается и от TestSys (где модуль тестирования и компилирования объединены в один), и от ejudge (где модуль компилирования работает на основном сервере системы).
Отделение управления тестированием от взаимодействия с пользователями позволяет, во-первых, упростить низкоуровневую часть системы, а во вторых, облегчить расширение её возможностей. Некоторую проблему при этом представляет интеграция системы с внешними системами, которая была успешно решена добавлением API в Web-интерфейс. API позволяет получать различные данные из системы (и вносить новые) путем выполнения специальных HTTP-запросов. Сами запросы и ответы API происходят в машиночитаемом виде.
Для взаимодействия друг с другом распределенных модулей используются следующие механизмы.
• Общая база данных (БД). Примером ее использования может служить взаимодействие web-интерфейса и тестирующих модулей системы: web-интерфейс добавляет в БД информацию об отправленных решениях, а диспетчеры тестирования периодически опрашивают БД о наличии еще не протестированных решений, и обратно — обновление БД диспетчерами тестирования отображается в Web-интерфейсе. В системах ejudge и TestSys такой механизм не используется, в силу большей централизованности архитектуры.
• Общая файловая система. Может служить, например, для взаимодействия web-ин-терфейса и тестирующих модулей: с одной стороны, тесты требуются тестирующим модулям для выполнения процедуры проверки решений, но, с другой стороны, требуется также
обеспечить возможность просмотра входных и выходных данных администраторам системы через web-интерфейс. Поэтому тесты хранятся на том же сервере, на котором расположен web-интерфейс и диспетчеры тестирования, а вспомогательные тестирующие модули получают их от диспетчеров тестирования по сети. Описанный механизм также решает проблему с синхронизацией тестов в том случае, когда используется несколько тестирующих серверов. Это стандартный механизм, использующийся во всех тестирующих системах.
• Сетевое взаимодействие. Осуществляется посредством собственного протокола, реализованного в виде надстройки над протоколом TCP. Это также стандартная практика.
• Сообщения потоков (Thread Messages) ОС Windows. Подобные сообщения отправляются из центра управления к другим модулям. Примером использования может служить остановка системы при остановке сервиса центра управления. В ejudge используется отправка сигналов ОС Unix, в TestSys подобные механизмы не применяются, поскольку, в силу более централизованной архитектуры, в них нет нужды.
Схема потоков данных между модулями системы приведена на рис. 1. На схеме не отражены очевидные управляющие взаимодействия, направленные от центра управления к остальным модулям, а также не отражены механизмы взаимодействия между модулями.
Представленная архитектура позволяет как развернуть все модули на одном сервере, так и организовать многосерверную конфигурацию. В последнем случае требуется выделить основной сервер, на котором будут работать диспетчеры тестирования и web-интер-фейс, и вспомогательные серверы, по которым можно произвольно распределять модули компилирования, тестирования и управления партиями.
Рис. 1. Схема потоков данных между модулями
С точки зрения архитектуры позволительно вынести БД на отдельный сервер, обеспечив взаимодействие связанных с ней модулей через сеть. При использовании разделяемой файловой системы web-интерфейс и диспетчеры тестирования также допустимо разместить на разных серверах.
ПРАКТИЧЕСКОЕ ПРИМЕНЕНИЕ РАЗРАБОТАННОЙ СИСТЕМЫ
На данный момент система с представленной архитектурой активно применяется в Клубе программистов ПетрГУ для проведения школьных и студенческих соревнований по программированию, а также для организации дистанционного обучения студентов и школьников [8]. В системе на данный момент создано более 300 контестов, добавлено более 2000 задач и отправлено более 55 000 решений.
Стоит отметить, что применение подобной системы для организации обучения позволяет значительно экономить время преподавателя, затрачиваемое на проверку решений. Конечно, по-прежнему необходима ручная проверка неформализуемых критериев оценки (таких как стиль кодирования, отсутствие плагиата и т. п.), однако время на проверку корректности работы программы уже не требуется. К сожалению, первоначальная подготовка задач для интеграции в систему может оказаться весьма трудоёмкой (поскольку нужно подготовить тесты, чекеры, написать и отформатировать условия и т. п.). Однако это компенсируется экономией времени в дальнейшем.
Например, для обучения школьников на первом году обучения в системе был создан контест из 79 задач. На подготовку всех задач ушло примерно 3 дня работы двух человек. Однако в дальнейшем время тратится только на консультирование учащихся и регистрацию новых участников в контесте. Этот контест успешно используется уже четвертый год.
Также система используется в курсе «Исследование операций», который читается на 4 курсе специальности «прикладная математика». В этом курсе студентам предлагается решать различные задачи линейной оптимизации. В этом курсе также активно применяется ручная проверка решений, проходящих все тесты, поскольку задачи у студентов идентичные и требуется предотвращать списывание.
Еще одним примером использования системы в учебном процессе может служить курс «Алгоритмы и структуры данных» (ранее «Комбинаторные алгоритмы»). Для него собран контест из 100 задач, разбитых на 5 заданий, по 20 вариантов в каждом. Преподаватель может самостоятельно указывать распределение заданий студентам, в зависимости от их уровня и сложности задач. Подготовка этого контеста заняла длительное время (около 20 человеко-дней) в связи со сложностью некоторых из предлагаемых задач. Контест используется два года, в нем приняло участие 85 студентов (32 в первый год и 53 во второй).
Со слов пользователей системы, экономится более 6 астрономических часов времени преподавателя на группу за семестр. При четырех группах экономия получается порядка рабочей недели. Также, появляется возможность оперативно влиять на неуспевающих студентов, а студенты могут проверять работоспособность своих программ, не дожидаясь преподавателя. Помимо этого, тестирование производится более надежно, повышая тем самым качество обучения.
Интересным применением системы оказался проект FastComputing, посвященный поиску наиболее оптимальных методов решения классических задач Computer Science [9].
Также система интегрирована с сайтом Клуба программистов ПетрГУ [8], на котором выложены различные контесты для участия, есть архив задач, содержащий задачи из разных олимпиад, возможность обсуждения задач и решений и система рейтинга пользователей.
Литература
1. ACM ICPC World Finals Rules [Электронный ресурс] / ACM. URL: http://icpc.baylor.edu/worldfinals/ rules#HScoringoftheFinals (дата обращения 17.07.2013).
2. Открытый Кубок имени Е.В. Панкратьева по программированию. [Электронный ресурс] URL: http://opencup.ru (дата обращения 25.06.2013).
3. Programming Contests at St. Petersburg State University [Электронный ресурс] URL: http:// acm.spbgu.ru/ (дата обращения 04.07.2013).
4. Кирюхин В. М., Окулов С. М. Методика решения задач по информатике. Международные олимпиады. М.: БИНОМ. Лаборатория знаний, 2007.
5. Летняя компьютерная школа [Электронный ресурс] / URL: http://lksh.ru (дата обращения 15.07.2013).
6. International Olympiad in Informatics [Электронный ресурс] URL: http://www.ioinformatics.org/ index.shtml (дата обращения: 12.07.2013).
7. Ejudge contest management system [Электронный ресурс] URL: http://ejudge.ru/ (дата обращения: 30.06.2013).
8. Клуб программистов ПетрГУ [Электронный ресурс] / ПетрГУ URL: http://acm.petrsu.ru/ (дата обращения 10.07.2013).
9. FastComputing. Поиск оптимальных способов решения классических задач Computer Science [Электронный ресурс] / ПетрГУ URL: http://fastcomputing.org/ (дата обращения 10.07.2013).
ARCHITECTURE OF SYSTEM FOR TESTING SOLUTIONS OF PROGRAMMING PROBLEMS
Denisov D. V.
Abstract
Nowadays it's very important to educate many qualified software developers. The most effective ways to do it include programming contests and remote courses. Requirements for software that helps conducting such events are very strict about effectiveness, reliability and security. This work describes common approaches to architecture of such a system and presents an architecture which keeps in mind weak spots in common solutions for the problem. Also work contains report about developing and deploying experience of system with such an architecture.
Keywords: programs testing, programming contests.
(q) Наши авторы, 2014. Our authors, 2014.
Денисов Денис Валерьевич, аспирант кафедры прикладной математики и кибернетики Петрозаводского государственного университета,