Целью тестрования программы является проверка того, что программа соответсвует своей спецификации, то есть выполняет те действия, которые от нее ожидаются. Поскольку ошибки в программе приводят к некорректным результатам или аварийной остановке программы (например, ошибкам сегментирования или ошибкам выполнения арифметических операций), то при тестировании выявляются скрытые дефекты программы. Результатом тестирования может являться описание условий возникновения ошибки. Например, если тестируется программа умножения целых чисел, то в процессе тестирования может быть выявлено, что при входных данных 2 и 2 программа выдает ответ 5. Поиск и исправление ошибки в исходном тексте программы называется отладкой. Тестирование и отладка суть разные процессы, которые могут выполняться разными людьми. Тестировщик вообще не обязан уметь программировать. Его задача – найти ошибку имея описание программы. Исправляют найденные ошибки программисты.
Выделяют разные типы тестирования программ. Во-первых, можно говорить об автоматическом и ручном тестировании. Автоматическое тестирование подразумевает выполнение набора тестов без вмешательства человека. Корректность работы программы проверяется автоматически (другой программой). Ручное тестирование, напротив, предполагает выполнение тестов человеком. Ручное тестирование может использоваться, например, при тестировании пользовательского интерфейса.
Во-вторых, существует юнит-тестирование (от английского unit) и
функциональное тестирование. Юнит-тесты, как правило, представляют
собой значительные по объему наборы тестов, проверяющих
корректность небольших элементов программы (юнитов). Примером
такого элемента является функция или класс. Желательно, чтобы
юнит-тесты приводили к высокому коэффициенту покрытия
исходного кода тестируемого фрагмента. Полное, 100-процентное,
покрытие означает, что при выполнении всего набора тестов каждая
строчка исходного кода программы выполнялась по крайней мере один
раз. Невыполнение какой-либо строчки исходного кода связано с
наличием условного оператора if
, поэтому юнит-тесты
должны содержать такие наборы входных данных, которые приводят к
прохождению всех условий и соответствующих им
веток else
.
Заметим, что существуют технические средства,
позволяющие оценивать покрытие программы набором тестов.
Добиться высокого показателя покрытия при тестировании крупной системы, включающей много частей, практически невозможно. Если система состоит из двух частей, каждая из которых требует по 10 тестов для получения полного покрытия, то для тестирования всей системы потребуется провести уже 100 тестов. Поэтому на более высоком уровне используют набор функциональных тестов, проверяющих, что система соответствует своей спецификации. Эти может быть несколько тестов на одно свойство системы. Такие тесты во многих случаях выполнятся вручную командой тестировщиков. Отдельные части системы проходят независимое unit-тестирование.
В-третьих, существует понятие регрессионного тестирования. Суть состоит в том, что наборы тестов накапливаются. Если в процессе тестирования была выявлена ошибка в программе, то при тестировании ее новой версии выполняются все тесты, которые выполнялись ранее, включая те тесты, которые выявили ошибку. Даже если ошибка была исправлена эти тесты будут использоваться при тестировании новых версий программы. Регрессионное тестирование позволяет избежать довольно часто возникающей ситуации, когда исправление одной ошибки приводит к повторному появлению другой, ранее уже исправленной, ошибки.
Что нужно тестировать? Для проверки работоспособности класса, функции или системы в целом нужно проводить тесты, проверяющие:
Конкретный набор тестов, естественно, зависит от содержания тестируемого класса, функции или программы. Однако приведенные выше группы тестов целесообразно реализовывать всегда. В многопользовательских системах, например, при разработке Web-систем, дополнительно проводится нагрузочное тестирование, при котором моделируется одновременная работа большого числа пользователей.