Критерии покрытия
Как видно из описания LL- и LR-анализаторов, основной момент их работы – принятие решения о дальнейших действиях на основании некоторых неполных данных (прочитанной части входного потока). Для LL-анализатора ситуации выбора соответствует пара (нетерминал на вершине стека, текущий входной символ), а для LR-анализатора – пара (символ состояния конечного автомата на вершине стека, текущий входной символ). Отсюда возникают следующие критерии покрытия для позитивных тестовых наборов:
(PLL) Покрытие всех пар
(нетерминал A, допустимый следующий токен t),
где пара (A,t) считается покрытой тогда и только тогда, когда в тестовом наборе существует последовательность токенов, являющаяся предложением целевого языка, имеющая вывод S
?A??t??. Иными словами, LL-анализатор, обрабатывая эту последовательность, получит ситуацию, когда на вершине стека будет находиться символ A, а текущим входным символом будет токен t. Модификация этого критерия для расширенной формы BNF грамматики была сформулирована в работе [1].(PLR) Покрытие всех пар
(символ si состояния конечного автомата, помеченный символом X переход из состояния si),
где пара (si,X) считается покрытой тогда и только тогда, когда в тестовом наборе существует предложение языка, имеющее вывод S
?X? такой, что префикс ? отвечает состоянию si. Или, что то же самое, LR-анализатор, обрабатывая это предложение получит ситуацию, когда на вершине стека будет находиться символ si, а началом текущего входного потока будет последовательность токенов, отвечающая символу X.Аналогично возникают следующие критерии покрытия и для негативных тестовых наборов (эти критерии имеют параметр r – количество “правильных” токенов, предшествующих “неправильному” токену):(NLLR) Пусть A – нетерминал. Последовательность токенов t1...tr назовем допустимой для A предпоследовательностью токенов, если существует сентенциальная форма ?t1...trA?, выводимая из стартового правила.
Рассмотрим объединение множеств
Заметим, что для такой грамматики покрытие всех пар (состояние конечного автомата, переход из этого состояния в другое) достигается при покрытии всех пунктов грамматики. Рассмотрим следующий критерий покрытия для наборов позитивных тестов: (WPLR) Покрытие всех пар (пункт ? = B > ?•X? грамматики G, допустимый первый токен t для символа X). Пара (?,t) считается покрытой тогда и только тогда, когда в тестовом наборе существует предложение языка, имеющее вывод S?B???X????t???.Для грамматик указанного типа этот критерий является более сильным, чем критерий PLR. Действительно, нетрудно показать, что каждое состояние определяется множеством своих базисных пунктов. Отсюда, поскольку для грамматик указанного класса подмножества базисных пунктов у разных состояний не пересекаются, то покрыв все пункты, мы покроем и все состояния. Аналогично можно сформулировать критерий покрытия для наборов негативных тестов: (WNLRR) Пусть ? = B > ?•? – пункт грамматики G. Последовательность токенов t1...tr назовем предпоследовательностью токенов допустимой для ?, если существует выводимая из стартового правила последовательность токенов ?t1...tr•?, имеющая вывод
т.е. ?t1...tr выводится из ??, а ? – из ??. Рассмотрим объединение множеств t1...tr по всем допустимым для ? предпоследовательностям токенов длины r < R. Критерий состоит в том, что все пары (?,t'), где t' из рассмотренного объединения, должны быть покрыты. Здесь покрытие пары (?,t') означает, что среди тестов имеется последовательность токенов, не принадлежащая целевому языку, такая, что некоторый ее префикс имеет вид ?t1...trt', где t1...tr – некоторая допустимая для ? предпоследовательность токенов такая, что t'? t1...tr.Сноски В общих словах мутационное тестирование состоит в следующем. Из тестируемого компонента получают множество его модификаций (мутантов), каждая из которых содержит ровно одну ошибку.
Говорят, что мутант убит, если на некоторых входных данных его выход отличен от выхода исходной программы. Если имеется множество тестовых входных данных для программы, то с помощью мутационного анализа (mutation analysis) можно оценить качество этих тестов. Именно, если имеется множество мутантов, то критерий покрытия говорит, что все мутанты должны быть убиты. В случае синтаксического анализатора логично в качестве мутируемого материала рассматривать грамматику языка, т.к. ошибочный анализатор фактически распознает другой язык. В этом случае грамматика-мутант будет убита, если найдется последовательность токенов, принадлежащая языку, задаваемому этой грамматикой-мутантом и не принадлежащая исходному языку (в терминах анализаторов это как раз будет означать, что анализатор-мутант распознал данное предложение, а исходный анализатор – нет, т.е. анализатор-мутант оказался убитым). 2 Существует связь между предлагаемым подходом и методом мутационного тестирования. Именно, для любой последовательности токенов, являющейся негативным тестом в описанном выше смысле (т.е. предложением языка, “испорченным” с помощью вставки/замены “нехорошего” токена) можно построить грамматику-мутант такую, что данный негативный тест будет являться предложением языка, описываемого этой грамматикой-мутантом. Одним из принципов мутационного тестирования является так называемый эффект взаимосвязи (coupling effect): при обнаружении простых ошибок будут обнаруживаться и более сложные (см. [16]). Согласно этому эффекту взаимосвязи, мутации должны быть простыми. Заметим, что предлагаемый подход вполне согласуется с этим принципом. Продолжение