11 подписчиков

Основы тестирования. Классы эквивалентности и поведение.

Перед тем как мы погрузимся в написание тестов, нам надлежит убедиться, что мы с вами одинаково понимаем теорию и терминологию тестирования. Мы расширим свой словарный запас и получим теоретическую основу для обсуждения тестирования.

Представьте, что вам необходимо протестировать новый дисплей для датчика давления автомобильных колес. Давление считывается с внешнего датчика, и гарантируется, что значение давления будет передано на наш 32-битный дисплей. Если давление больше 35 фунтов на квадратный дюйм (pounds per square inch, PSI), должен загореться сигнал "ИЗБЫТОЧНОЕ ДАВЛЕНИЕ", а все остальные сигналы должны быть отключены. Если давление находится в пределах от 0 до 20 PSI, должен загореться сигнал "НЕДОСТАТОЧНОЕ ДАВЛЕНИЕ", и все остальные сигналы должны быть отключены. Если значение давления оказывается отрицательным, должен загореться сигнал "ОШИБКА", и все остальные сигналы должны быть отключены.

Этот тест должен быть довольно простым. Имеется только одно входное значение, его тип известен, и выходные значения тоже известны. Мы исключаем экзогенные факторы, хотя тестировщику "железа" будет интересно узнать, что случится, если, скажем, провод между датчиком и дисплеем оборвется, или произойдет скачок напряжения, или... в общем, используйте свое воображение.

С чего надо начать подобное тестирование? Вам нужно подготовить некоторые входные значения и ожидаемые выходные (например, "отправить 15 PSI → увидеть, что горит сигнал „НЕДОСТАТОЧНОЕ ДАВЛЕНИЕ“ и все остальные сигналы выключены"). Вы можете исполнить тест и посмотреть, совпадает ли то, что происходит, с тем, что вы ожидали увидеть. Это суть тестирования — сверка ожидаемого поведения с наблюдаемым поведением, т. е. обеспечение того, что программа делает именно то, что вы ожидаете от нее в определенных обстоятельствах. Можно внести корректировки, дать советы и предостережения, но основа всего тестирования заключается в сравнении ожидаемого поведения с наблюдаемым.

Ваш менеджер хотел бы протестировать эту систему как можно быстрее и поручает вам создать четыре теста. Вооруженные знанием, что вам нужно сравнить ожидаемое поведение с наблюдаемым, вы решаете отправить значения –1, –111, –900 и –5, чтобы увидеть сигнал "ОШИБКА" в каждом случае, и при этом остальные сигналы не должны загораться. Волнуясь от того, что вы написали свои первые четыре теста, вы показываете их менеджеру, который хмурится и говорит: "Ты тестируешь только один класс эквивалентности!"

Класс эквивалентности (или эквивалентное разбиение) является набором входных данных, которые соответствуют одному выходному значению. Вы можете представить их как различные "группы" входных значений, которые делают что-то схожее. Это дает возможность тестировщикам создавать тесты, которые покрывают все составляющие функциональности и позволяют избежать избыточного тестирования только одной части (как в вышеприведенном примере, где класс эквивалентности "ОШИБКА" был протестирован четыре раза, в то время как другие ни одного).

Какие другие классы эквивалентности имеются в данном случае? Для того чтобы найти ответ, представьте все возможные варианты, которые вы можете получить на выходе:

1. Сигнал "ОШИБКА" загорается для PSI, равного –1 или меньше.

2. Сигнал "НЕДОСТАТОЧНОЕ ДАВЛЕНИЕ" загорается для PSI между 0 и 20 включительно.

3. Сигналы не загораются для PSI между 21 и 35 включительно — нормальные условия работы.

4. Сигнал "ИЗБЫТОЧНОЕ ДАВЛЕНИЕ" загорается для PSI от 36 и выше.

Математически вы можете связать группу входных значений и ожидаемое состояние на выходе:

1. [MININT, MININT + 1, ..., –2, –1] → только сигнал "ОШИБКА".

2. [0, 1, ..., 19, 20] → только сигнал "НЕДОСТАТОЧНОЕ ДАВЛЕНИЕ".

3. [21, 22, ..., 34, 35] → нет сигналов.

4. [36, 37, ..., MAXINT – 1, MAXINT] → только сигнал "ИЗБЫТОЧНОЕ ДАВЛЕНИЕ".

(Здесь MAXINT и MININT являются максимальным и минимальным значениями 32-битного целого числа соответственно.)

Мы только что разбили наши эквивалентные классы. Разбиение является определением наших эквивалентных классов и гарантированием того, что они не перекрывают друг друга, но при этом покрывают все входные значения. Другими словами, они должны поддерживать строгое разбиение. Например, из-за плохих или неправильно понятых требований мы сгенерировали следующее разбиение эквивалентных классов:

1. [–2, –1, 0, 1, 2] → только сигнал "ОШИБКА".

2. [3, 4, ..., 21, 22] → только сигнал "НЕДОСТАТОЧНОЕ ДАВЛЕНИЕ".

3. [20, 21, ..., 34, 35] → нет сигналов.

4. [36, 37, ..., 49, 50] → только сигнал "ИЗБЫТОЧНОЕ ДАВЛЕНИЕ".

Здесь есть две проблемы. Первая заключается в том, что все значения меньше –2 и больше 50 не привязаны к классам эквивалентности. Каким должно быть ожидаемое поведение, если датчик отправит значение 51? Это также рассматривается как ошибка? Или это "ИЗБЫТОЧНОЕ ДАВЛЕНИЕ"? В данном случае это не определено. Очень часто неопределенное поведение встречается при тестировании довольно сложных программных комплексов, но тестировщик ПО должен помогать в нахождении пробелов в покрытии и узнавать, что должно происходить (или, по крайней мере, происходит) в таких ситуациях.

Вторая и гораздо более неприятная проблема заключается в противоречивости принадлежности значений 20, 21 и 22. Они одновременно принадлежат к классам эквивалентности "НЕДОСТАТОЧНОЕ ДАВЛЕНИЕ" и "нет сигналов". Какое ожидаемое поведение для входного значения 21? В зависимости от того, какой эквивалентный класс вы рассматриваете, это может быть отсутствие сигналов или сигнал "НЕДОСТАТОЧНОЕ ДАВЛЕНИЕ". Это нарушение строгого разбиения, и вы легко можете увидеть, насколько проблематичным оно может быть.

Важно отметить, что эквивалентные классы не должны состоять из случаев, которые дают одинаковое выходное значение! Например, представим, что вы тестируете интернет-магазин. При стоимости заказа 100 долларов и менее предоставляется скидка 10%, а при заказе на 100,01 доллара и более — скидка 20%. И хотя здесь есть широкий диапазон выходных значений, поведение на выходе будет одинаковым для всех значений от 100 долларов и меньше и для всех значений от 100,01 доллара и больше. Они образуют два эквивалентных класса, и не будет отдельных классов для каждого индивидуального выходного значения (т. е. $10,00 → $9,00; $10,10 → $9,01 и т. д.).

Теперь, когда наши эквивалентные классы определены, можно написать тесты, которые покрывают всю функциональность дисплея. Мы можем отправить значение –2, чтобы протестировать класс эквивалентности "ОШИБКА", значение 10, чтобы протестировать класс эквивалентности "НЕДОСТАТОЧНОЕ ДАВЛЕНИЕ", значение 30 для тестирования класса эквивалентности "НЕТ СИГНАЛОВ" и значение 45, чтобы протестировать класс эквивалентности "ИЗБЫТОЧНОЕ ДАВЛЕНИЕ". Конечно, эти значения были выбраны, скорее, произвольно. В следующей главе мы рассмотрим, как выбирать определенные значения, чтобы увеличить шансы нахождения дефектов.