Top.Mail.Ru

Техники тест-дизайна

О техниках тест-дизайна написано очень много, о них рассказывают на всех курсах для тестировщиков и спрашивают практически на каждом интервью. Почему? Потому что умение проектировать тесты — это ключевой навык для тестировщика.

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

Именно здесь нам на нам помощь приходит тест-дизайн — процесс создания тестов, причем не любых, а именно таких, которые максимально полно покрывают требования к ПО и помогают обнаружить ошибки с наименьшими затратами. То есть результатом тест-дизайна будет являться набор тест-кейсов, которые ответят на вопрос “Как именно мы будем проверять ПО?”.

Для проектирования таких тестов существуют определенные принципы и специальные техники — техники тест-дизайна. Про них я и хочу рассказать, взглянуть на них со всех сторон и разобрать примеры из практики.

Компания Software Cats уже более пяти лет занимается аутстафом и аутсорсом по направлениям

Если у вас есть ИТ-проблема, оставьте ваши контакты, и мы поможем составить план ее решения.

Все техники тест-дизайна можно разделить на 3 группы:

  1. Основанные на опыте.
  2. Основанные на требованиях (Black-box).
  3. Основанные на коде (White-box).

Техники тест-дизайна, основанные на опыте

При создании таких тестов тестировщик полагается на интуицию, опыт и здравый смысл.

Исследовательское тестирование

Первая техника — это исследовательское тестирование (Exploratory Testing) — тестирование без заранее написанных тест-кейсов, на основе изучения системы в реальном времени.

Казалось бы, что тут сложного — бери и смотри, что “все открывается, все создается”.

Техника свободного тестирования (Freestyle Testing) — тестирование без структуры, на интуиции и опыте. Однако, это вряд ли он приведет к обязательному нахождению багов, если они имеются в системе, скорее при таком подходе баги можно найти только случайно.

Поэтому, при исследовательском тестировании рекомендуется применять и другие подходы..

Тестирование на основе труров (Guided Tour) — тестировщик выбирает определённый маршрут исследования — тур — и следует ему. То есть тур — это идеи и шаги по исследованию, объединенные определённой общей темой или целью. Например, тур по меню, тур по добавлению покупок в свою корзину, тур по рекомендуемым местам и т.д.

Использование эвристик (Heuristic Testing). Эвристики — это практические правила, помогающие находить проблемы быстрее, другими словами — это подсказки для тестирования. Стратегия тестирования в этом случае основывается на предыдущем опыте и информации о вероятности различных событий. Вот несколько примеров эвристик: Golden Path — сначала тестируем стандартный (золотой) путь пользователя, потом уже специфические и редкие сценарии; Bad Input — отправляем некорректные данные (недопустимые символы, пустые поля, слишком длинные строки); Simulate the Worst — моделируем наихудший сценарий, Least Privilege — меньше прав — безопаснее, у пользователя не должно быть больше прав, чем ему необходимо и т.д.

Предсказание ошибок

Предсказание ошибок (Error Guessing) — также относится к технике, основанной на опыте: тестировщик использует свой опыт, чтобы предсказать, где могут быть дефекты. Тестировщик, хорошо знакомый с системой, обычно знает, какие функциональности наиболее забагованы, каковы типичные дефекты для этой системы, какие модули наиболее уязвимы, какие есть стандартные ошибки, часто встречающиеся в аналогичных системах и т. д.

Несмотря на доступность и относительную простоту, методики тестирования, основанные на опыте, имеют ряд серьезных недостатков, что делает их недостаточными для полноценного тестирования. К таким недостаткам можно отнести:

  • эти техники не дают полного покрытия требований и не гарантируют, что все функциональности протестированы;
  • результат тестирования сильно зависит от опыта и ожиданий тестировщика;
  • высока вероятность пропуска критических багов из-за недостатка знаний;
  • cложно воспроизвести тесты, повторить найденные ошибки и проверить их после фикса;
  • методики, основанные на опыте, плохо автоматизируются;
  • не подходят для критически важного ПО, где существуют строгие стандарты безопасности и качества.

Техники тест-дизайна, основанные на требованиях (Black-box)

Этот подход фокусируется на проверке системы с точки зрения ее функциональности, не вдаваясь в детали реализации. Тестировщик рассматривает программное обеспечение как "черный ящик" — он знает, какие входные данные подает, но не знает, как именно система их обрабатывает. Главное здесь — убедиться, что поведение программы соответствует требованиям.

Такие техники помогают систематизировать тестирование и гарантируют, что ключевые сценарии работы системы будут покрыты. Давайте разберем основные методики.

Эквивалентное разбиение (Equivalence Partitioning)

Этот метод помогает сократить количество тестов без потери качества проверки. Входные данные делятся на группы (эквивалентные классы), в пределах которых система должна вести себя одинаково. Проверив один представитель из группы, мы предполагаем, что остальные значения дадут такой же результат.

Самый простой пример — поле ввода принимает числа от 1 до 100, то можно проверить три класса:

  • корректный (например, 50);
  • граничный (1 и 100);
  • некорректный (0 или 101, так как они вне диапазона).

Анализ граничных значений (Boundary Value Analysis)

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

Тот же пример — если допустимы числа от 1 до 100, проверяем:

  • 1 (нижнее граничное значение);
  • 0 и 2 (чуть ниже и выше граничного значения);
  • 100 (верхнее граничное значение);
  • 99 и 101 (чуть ниже и выше граничного значения).

Обычно техники эквивалентного разбиения и анализ граничных значений используются вместе.

Таблица принятия решений (Decision Table Testing)

Эта техника удобна, когда поведение системы зависит от комбинации нескольких условий. Мы строим таблицу, где в указываем возможные комбинации входных условий и ожидаемый результат.

Пример: интернет-магазин даст скидку 10%, если пользователь авторизован и сделал заказ более, чем на 5000 рублей.
Тест-кейс №1
Тест-кейс №2
Тест-кейс №3
Входные данные
Пользователь авторизован
Нет
Нет
Да
Входные данные
Заказ > 5000р
Нет
Да
Да
Ожидаемый результат
Нет скидки
Нет скидки
Нет скидки
Скидка 10%

Попарное тестирование (Pairwise Testing)

Когда параметров много, полное тестирование всех возможных комбинаций становится невозможным. Этот метод помогает сократить количество тестов, выбирая такие комбинации входных данных, чтобы каждая пара значений встречалась хотя бы раз.

Пример: если у нас три параметра и у каждого по три варианта, полный перебор даст 3×3×3=27 тестов. Попарное тестирование может сократить их до 9, сохраняя важное покрытие.

Рассмотрим на примере.
Таблица примеров

Цвет

Материал

Размер

Красный

Шерсть

S

Желтый

Хлопок

M

Синий

Шелк

L

Тест-кейсы
Цвет
Материал
Размер
1
Красный
Шерсть
S
2
Красный
Хлопок
M
3
Красный
Шелк
L
4
Желтый
Хлопок
L
5
Желтый
Шелк
S
6
Желтый
Шерсть
M
7
Синий
Шелк
M
8
Синий
Шерсть
L
9
Синий
Хлопок
S

Диаграммы переходов состояний (State Transition Testing)

Если система реагирует по-разному в зависимости от текущего состояния, эту технику применять особенно полезно. Мы строим диаграмму, где отображаем возможные состояния и переходы между ними в ответ на определенные действия.

Пример возможных состояний и переходов для процесса авторизации:

"Неавторизованный пользователь" → ввод логина и пароля → "Авторизованный пользователь".

"Авторизованный пользователь" → выход из системы → "Неавторизованный пользователь".

"Неавторизованный пользователь" → три неудачных попытки входа → "Аккаунт заблокирован".

"Аккаунт заблокирован" → сброс пароля администратором → "Неавторизованный пользователь".
Техники, основанные на требованиях, помогают структурировать тестирование и избежать субъективных пробелов, которые возможны при тестировании, основанном на опыте. Однако они требуют тщательного анализа документации, четкого понимания бизнес-логики и проработки возможных сценариев.

К недостаткам этих техник можно отнести:

  • они не позволяют проверить внутреннюю логику программы;
  • могут пропустить ошибки, связанные с реализацией алгоритмов;
  • требуют точных и полных требований, хорошего понимания системы.

Тем не менее, именно эти техники — основа качественного тестирования, позволяющая убедиться, что система делает именно то, что от нее ожидается.

Техники тест-дизайна, основанные на коде (White-box)

Когда мы говорим о техниках тест-дизайна, основанных на коде, основной акцент делается на проверку внутренней структуры системы. В отличие от подходов, ориентированных на функциональность, здесь тестировщик должен понимать, как устроен код, какие логические блоки и алгоритмы в нем используются, и на этой основе разрабатывать тесты. Основной принцип таких техник — это создание тестов, которые помогут выявить ошибки в реализации системы, а не только проверить её поведение.

Покрытие операторов (Statement Coverage)

Цель: Протестировать, что каждая строка кода выполнена хотя бы один раз.

Пример:
Проверяемый код.
public class StatementCoverageExample {
   public void exampleMethod(int a) {
       if (a > 10) {
           System.out.println("A is greater than 10");
       }
       System.out.println("This will always be printed");
   }
}
Тесты. Здесь оба теста выполняют различные части кода. В первом случае выполняются оба оператора, во втором — только второй оператор.
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

public class StatementCoverageExampleTest {

   @Test
   public void testStatementCoverage() {
       StatementCoverageExample example = new StatementCoverageExample();

       // Тест 1: a > 10, выполняется обе строки кода
       example.exampleMethod(15);

      // Тест 2: a <= 10, выполняется только вторая строка кода
       example.exampleMethod(5);
   }
}

Покрытие ветвей (Branch Coverage)

Цель: Проверить все возможные ветвления в коде (if, else, switch).

Пример:
Проверяемый код.
public class BranchCoverageExample {
   public void exampleMethod(int a) {
       if (a > 10) {
           System.out.println("A is greater than 10");
       } else {
           System.out.println("A is 10 or less");
       }
   }
}
Тесты. В данном примере тесты проверяют оба возможных ветвления: выполнение блока if и блока else.
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

public class BranchCoverageExampleTest {

   @Test
   public void testBranchCoverage() {
       BranchCoverageExample example = new BranchCoverageExample();

       // Тест 1: a > 10, условие if выполнится
       example.exampleMethod(15);

       // Тест 2: a <= 10, условие else выполнится
       example.exampleMethod(5);
   }
}

Покрытие условий (Condition Coverage)

Цель: Проверить все возможные значения условий внутри выражений.

Пример:
Проверяемый код.
public class ConditionCoverageExample {
   public void exampleMethod(int a, int b) {
       if (a > 10 && b < 5) {
           System.out.println("A is greater than 10 and B is less than 5");
       } else {
           System.out.println("Condition not met");
       }
   }
}
Тесты. Здесь проверяются все возможные значения для условий a > 10 и b < 5. Оба условия истинны. Первое условие ложно, второе — истинно. Первое условие истинно, второе — ложно.
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

public class ConditionCoverageExampleTest {

   @Test
   public void testConditionCoverage() {
       ConditionCoverageExample example = new ConditionCoverageExample();

       // Тест 1: a > 10, b < 5 (оба условия истинны)
       example.exampleMethod(15, 3);

       // Тест 2: a <= 10, b < 5 (условие a ложное)
       example.exampleMethod(5, 3);

       // Тест 3: a > 10, b >= 5 (условие b ложное)
       example.exampleMethod(15, 6);
   }
}
Все рассмотренные техники дополняют друг друга, и их комбинированное использование помогает достичь максимальной полноты тестирования.

Однако важно помнить, что выбор техники зависит от сложности системы, ее критичности и доступных временных ресурсов. Тестировщик, используя правильные подходы, может значительно повысить вероятность нахождения ошибок, улучшить покрытие системы и сократить время, затрачиваемое на тестирование.

Наша команда уже более пяти лет занимается реализацией проектов на Java и усилением команд по направлениям

За время существования компании, мы принимали участие в работе над более чем 100 проектами различного объема и длительности.

Если перед вами стоят вызовы, для достижения которых вам может понадобится наша экспертиза, просто напишите нам,

Мы договоримся с вами об онлайн-встрече, чтобы подробнее обсудить ваш проект и вашу проблему.
Руководитель отдела тестирования Software Cats

Еще почитать по теме:

    Обсудить проект_
    Если у вас есть ИТ-проблема, оставьте ваши контакты, и мы поможем составить план ее решения. Обещаем не слать спам.
    Нажимая, я говорю «Да»
    политике конфиденциальности
    hello@softwarecats.dev
    Новосибирск, ул. Демакова
    23/5, оф.308
    Контакты_

    Выполненные проекты: