Качество ПО (Software Quality) — совокупность характеристик программного обеспечения, относящихся к его способности удовлетворять установленные и предполагаемые потребности.
Примеры характеристик:
Обеспечение качества (Quality Assurance, QA) — совокупность мероприятий, направленных на то, чтобы программный продукт соответствовал заранее определенным требованиям (в соответствии со спецификацией) к качеству на всех этапах его жизненного цикла.
Тестирование ПО (Software Testing) — процесс анализа программного обеспечения и сопутствующей документации с целью выявления дефектов и оценки его качества.
Обеспечение качества направленно на предотвращение появления дефектов на всех этапах разработки, а тестирование направлено на их обнаружение в уже созданном продукте или его части; тестирование можно считать активностью внутри QA
Предварительным этапом тестирования программного обеспечения является тест-дизайн.
Тест-дизайн (Test Design, проектирование тестов) играет ключевую роль в процессе тестирования программного обеспечения. ISTQB определяет тест-дизайн как процедуру для вывода (и/или выбора) тестовых примеров на основе анализа функциональной и нефункциональной спецификаций компонента или системы, без обращения к ее внутренней структуре.
ISTQB (International Software Testing Qualifications Board) — это международная некоммерческая организация, которая занимается разработкой и стандартизацией в области тестирования программного обеспечения. Основана в 2002 году
Попытка "протестировать всё" является не только экономически нецелесообразной, но и технически невозможной, если мы говорим о современном программном обеспечении ("комбинаторный взрыв")
Тест-дизайн позволяет перейти от наивного подхода "исчерпывающего тестирования" к стратегии "умного тестирования".
Цель тест-дизайна: разработать оптимальное количество тест-кейсов, которые обеспечивают максимальное тестовое покрытие и с высокой вероятностью обнаруживают дефекты.
Задачи тест-дизайна:
Техники тест-дизайна, согласно классификации ISTQB, делятся на три основные категории, различающиеся по источнику информации, используемой для создания тестов:
Основная идея эквивалентного разбиения (Equivalence Class Partitioning, ECP) заключается в том, чтобы разделить всё множество входных данных на конечное число подмножеств, называемых "классами эквивалентности".
Отношением эквивалентности на множестве называется бинарное отношение , которое является рефлексивным (), симметричным (если , то ) и транзитивным (если и , то ).
Зададим отношение "обрабатывается системой также как и (приводит к тому же результату, что и)". Если на множестве задано отношение эквивалентности , то классом эквивалентности элемента a (обозначается как ) называется подмножество всех элементов , которые эквивалентны :
Объединение классов эквивалентности дает исходное множество
Предполагается, что система обрабатывает все значения из одного и того же класса одинаковым образом. Следовательно, для проверки поведения системы достаточно выбрать по одному элементу из каждого класса.
Классы эквивалентности обычно делятся на две категории:
Алгоритм применения техники разделения на классы эквивалентности состоит из следующих шагов:
Пусть есть поле для ввода возраста пользователя на форме регистрации. Требование: "Возраст должен быть в диапазоне от 18 до 59 лет включительно".
На основе этого требования можно выделить следующие классы эквивалентности:
Для тестирования достаточно выбрать по одному значению из каждого класса, например: 17, 35 и 60. Это позволяет тремя тест-кейсами покрыть весь спектр возможного поведения системы, связанного с этим полем, вместо тестирования сотен возможных значений.
Классы эквивалентности помогают писать осмысленные тест-кейсы и понимают сложность понимания системы
Для полного тестирования необходим набор тест-кейсов, в котором каждый класс эквивалентности участвует хотя бы один раз
Практический опыт показывает, что наибольшее количество ошибок в программном обеспечении возникает не внутри диапазонов, а на их границах
Это часто связано с тем, что разработчики могут ошибочно использовать строгие операторы сравнения вместо нестрогих или допускать ошибки типа "на единицу" (off-by-one errors).
Если нужно построить забор длиной 100 метров с секциями по 10 метров, потребуется 11 столбов, а не 10, так как столбы нужны и в начале, и в конце каждой секции
BVA предполагает выбор тестовых значений непосредственно на границе, а также по обе стороны от нее. Существует несколько подходов к выбору значений:
[min, max] выбираются значения: min-1, min, max, max+1min-1, min, min+1, max-1, max, max+1Для примера выше:
| Класс/Граница | Значение для теста | Ожидаемый результат | Техника |
|---|---|---|---|
| КЭ1: возраст < 18 | 17 | Ошибка: возраст слишком мал | BVA (min-1) |
| КЭ2: 18 <= возраст <= 59 | 18 | Успех | BVA (min) |
| КЭ2: 18 <= возраст <= 59 | 35 | Успех | ЕР (представитель) |
| КЭ2: 18 <= возраст <= 59 | 59 | Успех | BVA (max) |
| КЭЗ: возраст > 59 | 60 | Ошибка: возраст слишком велик | BVA (max+1) |
Для систем с несколькими входными параметрами BVA применяется к каждому параметру, в то время как остальные параметры удерживаются на своих "номинальных" (типичных) значениях
Техника для моделирования и тестирования бизнес-логики, где результат зависит от комбинации нескольких условий. Она позволяет представить комплексные правила в систематическом и наглядном виде, что помогает не только в проектировании тестов, но и в выявлении пробелов и противоречий в самих требованиях.
Стандартная таблица решений состоит из четырех квадрантов:
Пример:
Бизнес-правила:
Условия:
Действия:
| Правило 1 | Правило 2 | Правило 3 | Правило 4 | Правило 5 | Правило 6 | Правило 7 | Правило 8 | |
|---|---|---|---|---|---|---|---|---|
| Условия | ||||||||
| С1: VIP-клиент | Да | Да | Да | Да | Нет | Нет | Нет | Нет |
| С2: Заказ > 5000 | Да | Да | Нет | Нет | Да | Да | Нет | Нет |
| C3: Промокод "SALE20" | Да | Нет | Да | Нет | Да | Нет | Да | Нет |
| Действия | ||||||||
| A1: Скидка 10% | X | X | X | X | ||||
| A2: Бесплатная доставка | X | X | X | X | ||||
| A3: Скидка 20% | X | X | X | X |
Каждый столбец (правило) в этой таблице напрямую преобразуется в один или несколько тест-кейсов. Например, для Правила 1 необходимо создать тест-кейс, где VIP-пользователь делает заказ на сумму > 5000 руб. и применяет промокод, а затем проверить, что были применены обе скидки и бесплатная доставка.
Если локальные правила были корректно составлены на основе начальных бизнес-правил, то гарантируется, что такой набор тест-кейсов обеспечит тестирование всех комбинаций бизнес-правил
Является эволюционным развитием практики разработки через тестирование (Test-Driven Development, TDD). Ключевая идея заключается в смещении фокуса с технических аспектов ("тестирование кода") на бизнес-ориентированные аспекты ("определение поведения" системы).
Центральным элементом философии BDD является концепция "единого языка" (ubiquitous language), заимствованная из предметно-ориентированного проектирования (Domain-Driven Design, DDD). Этот язык представляет собой понятный всем участникам разработки способ описания функциональности системы. Вместо того чтобы бизнес-аналитики писали требования на одном языке, разработчики — код на другом, а тестировщики — тест-кейсы на третьем, BDD предлагает использовать единый формат, который служит одновременно и спецификацией, и автоматизированным тестом, и документацией.
Gherkin — это предметно-ориентированный язык, который используется для описания поведения системы в формате, понятном человеку.
Основные ключевые слова Gherkin:
Feature: название функциональности, которую нужно протестироватьScenario: конкретный сценарий использования этой функциональностиGiven: начальные условия или контекст (предусловие)When: действие, которое выполняет пользователь или системаThen: ожидаемый результат этого действияAnd / But: для добавления нескольких шагов к Given, When или Then# Файл: features/shopping_cart.feature
Feature: Управление корзиной покупок
Scenario: Добавление товаров и расчет итоговой суммы с учетом скидки
Given создана пустая корзина
When в корзину добавлен товар "Ноутбук" с ценой 1000 и в количестве 1
And в корзину добавлен товар "Мышь" с ценой 25 и в количестве 2
Then итоговая сумма в корзине должна составлять 1050
When к корзине применяется скидка в 10%
Then финальная цена с учетом скидки должна составлять 945.0
# Файл: cart.py
class ShoppingCart:
def __init__(self):
self.items = []
self.total = 0.0
def add_item(self, name, price, quantity):
"""Добавляет товар в корзину и пересчитывает сумму."""
self.items.append({"name": name, "price": price, "quantity": quantity})
self.calculate_total()
def calculate_total(self):
"""Вычисляет общую стоимость всех товаров в корзине."""
self.total = sum(item['price'] * item['quantity']
for item in self.items)
def apply_discount(self, percentage):
"""Применяет скидку к итоговой сумме."""
if not (0 < percentage <= 100):
raise ValueError("Скидка должна быть в диапазоне от 0 до 100")
discount_amount = self.total * (percentage / 100.0)
self.total -= discount_amount
def get_final_price(self):
"""Возвращает итоговую цену."""
return self.total
# Файл: features/steps/cart_steps.py
from behave import given, when, then
from cart import ShoppingCart
@given('создана пустая корзина')
def step_impl(context):
# Создаем экземпляр корзины и сохраняем его для следующих шагов
context.cart = ShoppingCart()
@when('в корзину добавлен товар "{name}" с ценой {price:d} и в количестве {quantity:d}')
def step_impl(context, name, price, quantity):
context.cart.add_item(name, price, quantity)
@then('итоговая сумма в корзине должна составлять {expected_total:d}')
def step_impl(context, expected_total):
assert context.cart.get_final_price() == expected_total, \
f"Ожидалось {expected_total}, но получили {context.cart.get_final_price()}"
@when('к корзине применяется скидка в {discount_percentage:d}%')
def step_impl(context, discount_percentage):
context.cart.apply_discount(discount_percentage)
@then('финальная цена с учетом скидки должна составлять {final_price:g}')
def step_impl(context, final_price):
assert context.cart.get_final_price() == final_price, \
f"Ожидалось {final_price}, но получили {context.cart.get_final_price()}"
Ход работы:
Запуск: запускается behave из командной строки в корне проекта.
Чтение Gherkin: Behave находит файл shopping_cart.feature и начинает выполнять сценарий по шагам
Шаг "Given": Behave находит функцию с декоратором @given('создана пустая корзина'), выполняет ее код и создает экземпляр ShoppingCart в context
Шаг "When": для каждого шага "When" Behave вызывает соответствующую функцию, которая, в свою очередь, вызывает методы context.cart.add_item() или context.cart.apply_discount()
Шаг "Then": Behave вызывает функции-проверки, которые с помощью assert сравнивают фактический результат (полученный из context.cart) с ожидаемым результатом (указанным в .feature-файле).
