Тестирование программы markov
Программа markov из главы 3 достаточно сложна, поэтому ее надо особенно тщательно оттестировать. Производит она белиберду, которую трудно проверить на корректность, и, кроме того, мы написали несколько версий на разных языках. И последнее затруднение – вывод программы случаен по определению, и по идее при каждом запуске должен изменяться. Как же применить уроки данной главы к тестированию такой программы?
Первый набор тестов состоит из нескольких крошечных файлов – для проверки граничных условий. Цель этого этапа – убедиться в том, что программа работает нормально при вводе размером всего в несколько слов. Для префиксов длиной два мы использовали пять файлов, содержащих, соответственно (по одному слову-символу на строку!):
Для.каждого из приведенных файлов вывод должен быть тождественен вводу. При этой проверке были обнаружены несколько ошибок на единицу при инициализации таблицы, а также при запуске и остановке генератора.
Второй тест проверял сохранность данных. Для префиксов из двух слов каждое слово, каждая пара слов и каждая тройка слов в выходном тексте должны содержаться также и во введенном тексте. Мы написали программу на Awk, которая считывает входной текст в гигантский массив, строит массивы пар и троек слов, потом считывает вывод программы в другой массив и сравнивает массивы:
Мы не пытались сделать этот тест особо эффективным, наоборот, хотели лишь написать как можно более простую программу. Сравнение 10 000 слов вывода с 42 685 словами ввода занимает у нее шесть или семь секунд – не дольше, чем компилируются некоторые версии самой программы markov. Проверка сохранности данных обнаружила важную ошибку в версии, написанной на Java: программа иногда переписывала значения таблицы, поскольку использовала ссылки вместо того, чтобы создавать копии префиксов.
Приведенный тест иллюстрирует принцип, согласно которому проще бывает проверить свойства результата, чем получить этот результат. Например, проще удостовериться в том, что файл отсортирован, чем выполнить саму сортировку.
Третий тест – статистический по своей природе. Ввод состоит из последовательностей:
abcabc… abd…
В которых на одно вхождение abd приходится десять вхождений abc. Теперь, если генератор случайных чисел работает правильно, в выводе должно быть примерно в десять раз больше с, чем d. Проверяли мы это, естественно, с помощью freq.
Статистический тест показал, что ранняя Java-версия программы, в которой с каждым суффиксом ассоциировался счетчик, выводит около, двадцати с на каждое d, то есть в два раза больше, чем предполагалось. Немного поломав голову, мы осознали, что генератор случайных чисел в Java возвращает как положительные, так и отрицательные целые значения; множитель два появился, таким образом, из-за того, что диапазон значений для генератора был в два раза больше ожидаемого и поэтому первый элемент в списке выпадал чаще (а это была именно буква с). Исправить ошибку оказалось гораздо проще, чем найти, – достаточно взять значения по модулю. Без этого теста мы никогда не нашли бы ошибки, на глаз вывод выглядел совершенно нормально.
Наконец, мы скормили программе нормальный английский текст для того, чтобы убедиться, что на выходе будет очаровательная нелепица. Естественно, этот тест мы производили и на ранних стадиях написания программы. Однако теперь, даже убедившись, что программа нормально обрабатывает те данные, для которых, собственно, и создавалась, мы не прекратили тестирования. Всегда приятно оттестировать простые случаи и убедиться, что все в порядке, однако трудные случаи также должны быть проверены. Автоматизированное, систематическое тестирование – единственный способ обойти все ловушки.
Весь процесс тестирования программы markov был автоматизирован. Специальный скрипт генерировал необходимые входные данные, запускал тесты, отмечал время их работы и распечатывал аномальные результаты вывода. Скрипт мы написали настраиваемый, так что одни и те же тесты можно было применить к версии на любом языке: каждый раз при внесении изменений в одну из программ мы без дополнительных усилий прогоняли на ней все тесты.