Представим, что мы тестируем новую программу "Уменьшатель", которая берет строку и делает ее буквы строчными. Заказчик не предоставил никакого дополнительного описания задачи, потому что она кажется очевидной — входной текст может быть в нижнем регистре, а может и не быть, данные на выходе должны быть той же строкой, но все прописные буквы должны стать строчными. Метод, решающий эту задачу в программе, имеет следующую сигнатуру:
public String lowerify(String S)
Заказчик настаивает, что больше ничего не нужно знать, чтобы начать тестирование. Если бы вам было поручено такое тестирование, какие бы вопросы вы задали для того, чтобы создать тест-план? Другими словами, какие требования вы бы постарались вытянуть из заказчика?
1. Какая кодировка символов будет использоваться — UTF-9, ASCII, EBCDIC или что-то другое?
2. Какая максимальная длина обрабатываемых данных предполагается? То, что хорошо работает на нескольких словах, может начать вести себя по-другому, если на вход подать несколько терабайт текста.
3. Что должно происходить, если входной текст написан на языке, отличном от английского? И что делать, если в этом языке нет понятия прописных и строчных букв?
4. Что должна делать программа, если во время ее работы пользователь нажмет комбинацию клавиш + или выполнит любую другую команду остановки программы?
5. Должна ли эта программа уметь читать данные из сети? Если да, то что нужно делать в случае проблем с сетью — попытаться прочитать данные снова, прекратить работу, показать ошибку или что-то еще?
Уверенность в том, что у вас есть правильные ответы на эти вопросы, является частью валидации программы. Вы хотите тестировать не то, что пользователь хочет получить от программы.
Вы разобрались, что хочет заказчик, но тем не менее еще остается над чем поработать. Вам нужно убедиться, что программа работает в нормальных условиях и обрабатывает разнообразные входные данные. Вот несколько вариантов входных данных, позволяющих протестировать работу программы в различных случаях:
1. Строка со всеми прописными буквами, например "ABCDEFG". 2. Строка, в которой все буквы уже переведены в нижний регистр, например "lmnop".
3. Строка с небуквенными символами, например "786*%0()[]".
4. Строка, в которой смешаны буквы в верхнем и нижнем регистрах, например "VwXyZ".
5. Строка со спецсимволами, такими как возврат каретки и нулевой символ, т. е. \r\n\o.
6. Пустая строка.
7. Очень длинная строка - скажем, текст из большой книги, оцифрованной в рамках "Проекта „Гутенберг“".
8. Исполняемый код.
9. Бинарные данные.
10. Строка, внутри которой встречаются маркеры конца файла (EOF).
Можете ли вы придумать какие-либо другие возможные входные данные, которые способны вызвать ошибку или неправильный результат? Внешние факторы также могут рассматриваться.
Что произойдет, если...
1. У системы закончится память во время обработки текста?
2. Процессор обрабатывает множество различных процессов, и система из-за этого не отвечает на запросы?
3. Сетевое соединение оборвано в самый разгар обработки данных?
Важно отметить, что практически невозможно исчерпывающе протестировать все комбинации входных данных. Даже если бы мы собирались протестировать входные данные, ограниченные 10 символами из цифр и букв, и проигнорировать все внешние факторы, тогда бы у вас получилось более трех квадриллионов тесткейсов. Так как строки могут быть произвольной длины (их ограничивает объем памяти компьютера), и существует множество внешних факторов, которые можно было бы учесть, выполнение всеобъемлющего тест-плана для этой функции заняло бы миллиарды лет! Даже из этого простого примера легко понять, что тестирование может быть очень сложным процессом, полным неопределенности и трудных решений о том, на чем следует сфокусироваться. Тестировщику предстоит не только решать эти неопределенности, но и устанавливать, сколько усилий и времени следует тратить на них. Чем больше усилий вы вложите в какую-то часть тестирования, тем меньше времени останется на другое. Помните это, разрабатывая тестовую стратегию, — время, за которое вы должны выполнить проект, может изменяться, но оно всегда конечное, и всегда существуют различные приоритеты, которыми вам придется жонглировать, чтобы обеспечить качество ПО.
Помните, что причиной проведения тестирования ПО являются оценка и, если возможно, уменьшение риска для заинтересованных лиц. Понимание возможных рисков само по себе может уменьшить риск. В конце концов, непротестированное программное обеспечение, которое никогда не запускалось, может быть идеальным (теоретически, по крайней мере) или не работать совсем. Тестирование помогает рассчитать, где между этими двумя экстремумами на самом деле находится программное обеспечение. Это поможет нам понять, являются ли проблемы с ПО тривиальными, или же из-за них следует отложить выпуск программы, потому что бóльшая часть функционала не работает. Помогая определить уровень риска, тестировщики позволяют другим участвующим заинтересованным лицам принять соответствующие решения.