"70% чего?" или различные метрики измерения тестового покрытия
В процессе разработки тестов для программного продукта, возникает вопрос: "сколько и какие тесты необходимо написать?". Доклад описывает подходы, позволяющие с разных сторон оценить насколько полно набор тестов проверяет приложение. Слушатель познакомится с методами и метриками измерения качества тестов применяемыми в компании Оракл, такими как покрытие методов, линейных блоков, покрытие утверждений спецификации. Доклад будет интересен и тем, кто никогда не сталкивался с измерением покрытия кода, так и тем, кто постоянно применяет его на практике.
4. Оценка тестирования
Программный
Техническое задание продукт
Тесты
• Нужны ли еще тесты?
• Если нужны, то на какие компоненты?
• Сколько стоят тесты?
4
5. Метрика - это мера, позволяющая получить
численное значение некоторого свойства
Объект Свойство Значение
Программа Размер исходного кода, байт 10 430 202
Зебра Количество полосок, шт. 29
Больница Средняя температура, °С 37,1102
5
6. Метрики тестового покрытия
• Покрытие исходного кода
– Методов
– Строк
– Линейных блоков
– Условий (branch)
– Путей или предикатов
• Покрытие требований
– В ширину (Breadth coverage)
– В глубину (Deapth coverage)
6
7. Покрытие методов
class СтиральнаяМашина {
Считать ли метод public void делать_всё() {
протестированным, если он стирать(20);
полоскать(15);
вызван не напрямую из теста? отжимать(700);
}
public void стирать(int time) {...}
• Вариант ДА: 4 из 4 = 100% public void полоскать(int time) {...}
• Вариант НЕТ: 1 из 4 = 25% public void отжимать(int time) {...}
}
void test() { машина.делать_всё(); }
7
8. Способы измерения покрытия кода
• Инструментация исходного кода
• Инструментация байт кода
– перед исполнением
– во время загрузки классов (java -javaagent:cov.jar …)
• Подписка на события VM
– JVM TI
• Статический анализ классов приложения и тестов
8
9. Инструментация
class Счет {
void раз_два() {
Collector.data[191]++;
делай_раз();
делай_два();
class Счет { }
void раз_два() { }
делай_раз();
делай_два();
} public class Collector {
} long[] data = new long[10000];
}
...
191=метод Счет.раз_два()
...
9
10. Статический анализ
• Шаг 1: Сканировать приложение
– Список классов
– Список методов
• Шаг 2: Сканировать тесты
– Поиск вызовов методов приложения
ApiCover http://sigtest.java.net
10
11. Динамический и статический анализ
Динамика
Вызван Не вызван
Статика
Метод Есть тест, который
Присутствует
протестирован не запускается
Метод, который Метод не
Отсутствует
вызван не напрямую протестирован
11
12. Строки или линейные блоки?
public class МойКласс {
public static int вычислить(int n) {
if (n != 0) {
System.out.println("Дано" + n);
Датчик датчик = new Датчик(); Покрытие строк
int воздух = датчик.воздух(); 8 из 10 = 80%
int вода = датчик.вода();
int m = (вода + воздух) / n;
System.out.println("Итог: " + m); Покрытие блоков
return m;
} 1 из 2 = 50%
return new Датчик().вода() / n;
}
}
@test void testCalc() {
assetFalse(МойКласс.вычислить(10) != 10);
}
12
13. Покрытие требований
class Собака {
/** Издает громкий звук */
public void лаять() { // TO DO }
/** Кусает за ногу */
public void кусать() { // TO DO } Покрытие методов
3 из 3 = 100%
/** Крепко спит 30 минут */
public void спать() { // TO DO }
} Покрытие требований:
0 из 3 = 0%
сlass Тест {
void test() {
Собака щенок = new Собака();
щенок.лаять();
щенок.кусать();
щенок.спать();
}
}
13
14. Процесс покрытия требований
• Перевести техническое задание в список утверждений
• Связать тесты и утверждения
• Получить отчет
14
15. Покрытие в глубину
• У1: "Модуль А выдает значение числа π"
• У2: "Модуль В реализует операцию сложения"
Список логических тестов для утверждения
• У1:
– Выдаваемое значение: 3,14159265359
• У2
– Сложение положительного и отрицательного
– Сложение с 0
– Переполнение
– ...
15
16. Метод аппроксимации
• Оценить общее количество утверждений
• Определить классы сложности утверждений
• Выбрать по 10-20 случайных утверждений для каждого
класса сложности
• Посчитать покрытие в глубину и в ширину для выбранных
случайных утверждений
• Аппроксимировать результат
16
17. Стратегия эффективного тестирования
• Вызвать по методу из 90% классов
• Вызвать 90% методов
• Добиться 70% покрытия строк
80 100
Выявленные ошибки
90
70
80
Покрытие строк
60
70
50
60
40 50
40
30
30
20
20
10
10
0 Время 0
Время
0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 4 8
Эффективный подход Линейный подход Эффективный подход Линейный подход
17
18. Почему не нужно 100%
• Неэффективно
– 20% кода — 80% ошибок
– Тривиальный код
• Дорого
– Труднодоступный код
– Обработка исключений
• Нет гарантии отсутствия ошибок
• Минусы огромного числа тестов:
• Возрастает время прогона
• Много падений по одной причине
• Больше затрат на переделку
18