Приёмочные тесты интерпретатора

Приёмочные тесты интерпретатора #

Концептуальные требования к тестам #

Приёмочные тесты должны быть одновременно функциональными и интеграционными. Объяснение:

  1. Приёмочные тесты (Acceptance tests) проверяют пригодность ПО для решаемой задачи; в контексте интерпретатора они могут:
    • проверять отдельные возможности языка — например, арифметические операции +, -, *, /
    • проверять полноценные программы — например, вычисление площади круга или сортировку пузырьком
  2. Функциональные тесты (Functional tests) проверяют интерфейс программы вместо деталей реализации; в контексте интерпретатора они могут запускать CLI либо эмулировать запуск CLI, вызывая внутренние

Реализация тестов #

Приёмочные тесты должны запускать интерпретатор целиком, подменяя средства ввода/вывода через инъекцию зависимостей в конструктор или параметры.

Для реализации приёмочных тестов можно использовать три подхода:

  1. Использовать Gherkin для описания тестов — см. Пример PsTiger
  2. Описать тесты в файлах — см. Пример MiniJavaGo
    • каталог содержит пары файлов {name}.java и {name}.stdout
    • тесты сканируют каталог и выполняют все файлы {name}.java в интерпретаторе, а ожидаемый вывод читают из {name}.stdout
  3. Использовать параметризованные тесты — см. Пример PsTigerCpp

Тестовые дублёры #

Для приёмочных тестов следует использовать тестовые дублёры только для изоляции тестируемого кода от внепроцессных зависимостей. Среди тестовых дублёров лучше использовать Fake-объекты.

В примерах этого курса есть тестовые дублёры. Так, Пример PsTiger содержит:

  1. Интерфейс IEnvironment, который абстрагирует ввод/вывод
  2. Класс ConsoleEnvironment, которая реализует консольный ввод/вывод
  3. Класс FakeEnvironment — тестовый дублёр
    • используется в приёмочных тестах, чтобы задавать ввод и перехватывать вывод интерпретатора
    • является Fake-объектом — то есть подделкой, которая для тестируемой системы выглядит неотличимой от оригинала

Требования к покрытию тестами #

Вы должны убедиться, что:

  1. Парсер покрыт тестами на 80% и выше — проверяйте это по line coverage.
  2. На разбор каждого правила грамматики есть хотя бы один тест.
  3. На правила с несколькими вариантами (оператор | в EBNF) есть по одному тесту на каждый вариант.

Правило «есть хотя бы один тест» следует трактовать с умом: вы можете одним тестом покрыть сразу несколько правил.

Например, вычисление следующей программы позволяет проверить одновременно:

  • разбор точки входа;
  • разбор 3 арифметических операторов.
/* Сложение, умножение и унарный минус */
/* Ожидаемый результат: 80 */

class AddMultiply {
    public static void main(String [] a) {
        System.out.println(10 + 7 * (2 * 3 + 4) + 5 + -5);
    }
}

См. также Анализ покрытия тестами кода для C#/.NET