Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

Тестирование

Раздел: Тестирование > Тест дизайн > Тестовое Покрытие

Тестовое Покрытие (Test Coverage)

Если рассматривать тестирование как «проверку соответствия между реальным и ожидаемым поведением программы, осуществляемая на конечном наборе тестов», то именно этот конечный набор тестов и будет определять тестовое покрытие:

Чем выше требуемый уровень тестового покрытия, тем больше тестов будет выбрано, для проверки тестируемых требований или исполняемого кода.

Сложность современного программного обеспечения и инфраструктуры сделало невыполнимой задачу проведения тестирования со 100% тестовым покрытием. Поэтому для разработки набора тестов, обеспечивающего более менее высокий уровень покрытия можно использовать специальные инструменты либо техники тест дизайна.

Существуют следущие подходы к оценке и измерению тестового покрытия:

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

Покрытие требований (Requirements Coverage)

Расчет тестового покрытия относительно требований проводится по формуле:

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

Покрытие кода (Code Coverage)

Расчет тестового покрытия относительно исполняемого кода программного обеспечения проводится по формуле:

В настоящее время существует инструментарий (например: Clover), позволяющий проанализировать в какие строки были вхождения во время проведения тестирования, благодаря чему можно значительно увеличить покрытие, добавив новые тесты для конкретных случаев, а также избавиться от дублирующих тестов. Проведение такого анализа кода и последующая оптимизация покрытия достаточно легко реализуется в рамках тестирования белого ящика (white-box testing) при модульном, интеграционном и системном тестировании; при тестировании же черного ящика (black-box testing) задача становится довольно дорогостоящей, так как требует много времени и ресурсов на установку, конфигурацию и анализ результатов работы, как со стороны тестировщиков, так и разработчиков.

Тестовое покрытие на базе анализа потока управления

Фундаментом для тестирования потоков управления является построение графов потоков управления (Control Flow Graph), основными блоками которых являются:

Для тестирования потоков управления определены разные уровни тестового покрытия:

УровеньНазваниеКраткое описание
Уровень 0“Тестируй все что протестируешь, пользователи протестируют остальное” На английском языке это звучит намного элегантнее: “Test whatever you test, users will test the rest”
Уровень 1Покрытие операторовКаждый оператор должен быть выполнен как минимум один раз.
Уровень 2Покрытие альтернатив [2] / Покрытие ветвейКаждый узел с ветвлением (альтернатива) выполнен как минимум один раз.
Уровень 3Покрытие условийКаждое условие, имеющее TRUE и FALSE на выходе, выполнено как минимум один раз.
Уровень 4Покрытие условий альтернативТестовые случаи создаются для каждого условия и альтернативы
Уровень 5Покрытие множественных условийДостигается покрытие альтернатив, условий и условий альтернатив (Уровни 2, 3 и 4)
Уровень 6“Покрытие бесконечного числа путей”Если, в случае зацикливания, количество путей становится бесконечным, допускается существенное их сокращение, ограничивая количество циклов выполнения, для уменьшения числа тестовых случаев.
Уровень 7Покрытие путейВсе пути должны быть проверены

Таблица 1. Уровни тестового покрытия

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

[1] A practitioner’s Guide to Software Test Design. Lee Copeland

[2] Стандартный глоссарий терминов, используемых в тестировании программного обеспечения Версия 2.0 (от 4 декабря 2008), Подготовлен ‘Glossary Working Party’ International Software Testing Qualifications Board

Источник

Полное покрытие кода

Инструмент тестирования nose

Изначальный пример кода

#!/usr/bin/env python
import operator

Код работает только на Python 2.6 и не совместим с Python 3. Код сохранен в файле main.py.

Юнит-тесты

Начнем с простых тестов:

import unittest
from main import factorial

OK

Добавим еще один класс для стопроцентного покрытия:

class FakeStream :

def readline ( self ):
return ‘5’

Выводы

Адаптация под Python 3

#!/usr/bin/env python
import operator

Теперь программу можно запускать:
$ python3 main.py
Enter the positive number: 0
0! = 1

Значит ли это, что программа рабочая? Нет! Она рабочая только до вызова reduce, что нам и показывают тесты:
$ nosetests3
E. E
======================================================================
ERROR: test_calculation (tests.TestFactorial)
———————————————————————-
Traceback (most recent call last):
File «/home/nuald/workspace/factorial/tests.py», line 9, in test_calculation
self.assertEqual(720, factorial(6))
File «/home/nuald/workspace/factorial/main.py», line 12, in factorial
return reduce(operator.mul, range(1, n + 1))
NameError: global name ‘reduce’ is not defined

FAILED (errors=2)

В данном примере все это можно было обнаружить и ручным тестированием. Однако на больших проектах только юнит-тестирование поможет обнаружить такого рода ошибки. И только полное покрытие кода может гарантировать что практически все несоответствия кода и API были устранены.

Ну и собственно, рабочий код, полностью совместимый между Python 2.6 и Python 3:

#!/usr/bin/env python
import operator
from functools import reduce

import sys
import unittest
from main import factorial

class FakeStream :

def readline ( self ):
return ‘5’

Источник

Тестирование программного кода (покрытия)

6.3. Покрытие программного кода

6.3.1. Понятие покрытия

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

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

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

6.3.2. Уровни покрытия

6.3.3. По строкам программного кода (Statement Coverage)

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

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

Например, для полного покрытия всех строк следующего участка программного кода на языке C достаточно одного тестового примера:

Другой особенностью данного метода является зависимость уровня покрытия от структуры программного кода. На практике часто не требуется 100% покрытия программного кода, вместо этого устанавливается допустимый уровень покрытия, например 75%. Проблемы могут возникнуть при покрытии следующего фрагмента программного кода:

6.3.3.1. По веткам условных операторов (Decision Coverage)

В отличие от предыдущего уровня покрытия данный метод учитывает покрытие условных операторов с пустыми ветками. Так, для покрытия по веткам участка программного кода

необходимы два тестовых примера:

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

полное покрытие по веткам может быть достигнуто при помощи двух тестовых примеров:

6.3.3.2. По компонентам логических условий

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

6.3.3.3. Покрытие по условиям (Condition Coverage)

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

для покрытия по условиям потребуется два тестовых примера:

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

6.3.3.4. Покрытие по веткам/условиям (Condition/Decision Coverage)

Для покрытия рассмотренного выше фрагмента с условием condition1 | condition2 потребуется 2 тестовых примера:

6.3.3.5. Покрытие по всем условиям (Multiple Condition Coverage)

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

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

Еще одним недостатком метода является зависимость количества тестовых примеров от структуры логического выражения. Так, для условий, содержащих одинаковое количество компонент и логических операций:

Источник

Проблемы тестирования: почему 100% покрытие кода это плохо

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

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

Материал подготовлен на основе выступления разработчика Positive Technologies Ивана Цыганова на конференции Moscow Python Conf (слайды, видео).

Зачем мы пишем тесты

ИБ-эксперты Positive Technologies проводят более 200 аудитов информационной безопасности в год, но мы прежде всего продуктовая компания. Один из наших продуктов — система контроля защищенности и соответствия стандартам MaxPatrol.

Продукт состоит из трех больших подсистем:

Нужно ли 100% покрытие

Здесь есть интересный момент — многие специалисты считают, что проверка покрытия тестами говорит о качестве тестирования. На самом деле это совершенно не так. Да, это хорошая ачивка («у нас 100% coverage!»), но это не означает того, что проект полностью протестирован. Стопроцентное покрытие говорит лишь о стопроцентном покрытии кода тестами, и ни о чем больше.

Для Python де-факто стандартом проверки покрытия является библиотека coverage.py. Она позволяет проверить покрытие кода тестами, у нее есть плагин для pytest. В основном, библиотека работает, но не всегда.

Пример — код ниже покрыт тестами на 100%. И в этом примере претензий к работе coverage.py нет.

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

Но на более сложной функции один тест дает 100% покрытие, при этом функция остается не протестированной. Мы не проверяем ситуацию, когда единственный ‘if’ функции обернется в False.

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

У библиотеки есть еще один режим работы, который позволяет отслеживать покрытие ветвей исполнения кода. Если запустить проверку в этом режиме, то будет видно, что не покрыт переход из третей в пятую строку кода. Это означает, что на всех запусках тестов мы никогда не попадали из третьей строки сразу в пятую, а всегда попадали в четвертую, то есть “if” на всех тестовых данных оборачивался в True.

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

Как считается покрытие

Существует простая формула для расчета покрытия кода тестами:

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

Coverage.py работает по такой схеме — сначала библиотека берет все исходники и прогоняет через собственный анализатор для получения списка инструкций. Этот анализатор обходит все токены и отмечает «интересные» с его точки зрения факты, затем компилирует код, обходит получившийся code-object и сохраняет номера строк. При обходе токенов он запоминает определения классов, «сворачивает» многострочные выражения и исключает комментарии.

Переходы между строками считаются примерно так же:

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

Опять берется исходный код и анализируется классом AstArcAnalyzer для получения пары значений — из какой строки в какую возможен переход. AstArcAnalyzer обходит AST-дерево исходников с корневой ноды, при этом каждый тип нод отрабатывается отдельно.
Далее нужно каким-то образом получить информацию о реально выполненных строках — для этого в coverage.py используется функция settrace. Она позволяет нам установить свою функцию трассировки, которая будет вызываться при наступлении некоторых событий.

Например, при наступлении события “call” мы понимаем, что была вызвана функция или мы вошли в генератор… В этом случае библиотека сохраняет данные предыдущего контекста, начинает собирать данные нового контекста, учитывая особенности генераторов. Еще одно интересующее нас событие — событие “line”. В этом случае запоминается выполняемая строка и переход между строками. Событие return отмечает выход из контекста — тут важно помнить, что yield также вызывает наступление события “return”.

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

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

Что может пойти не так

Рассмотрим простой пример — вызов некоторой функции с условием при передаче параметров.

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

Оператор if будет покрыт всегда. И мы никогда не узнаем, что это условие всегда оборачивалось в false.

Проблема возникнет и при использовании lambda — внутрь этой функции coverage.py не заглядывает и не скажет нам о том, что внутри что-то не покрыто. Не сможет библиотека разобраться и с list, dict, set-comprehensions.

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

Делаем мир лучше

Возьмем простой пример непокрываемого кода:

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

Допустим, мы хотим покрыть его и знать, когда не срабатывало условие “or c”. Ни один режим coverage.py не позволит этого сделать. Что можно попробовать сделать в этом случае?

Можно установить собственную функцию трассировки, посмотреть на результат ее работы и сделать выводы. То есть, фактически, повторить то, что делает coverage.py. Этот вариант не подходит, поскольку мы имеем ограниченное количество событий: call, line, return, exception. Маленькие частички оператора if мы никогда не увидим.

Другой вариант — использовать модуль ast.NodeTransformer. С его помощью мы можем обойти дерево, обернуть в «нечто» каждую ноду, запустить и посмотреть, что выполнялось. Проблема здесь в том, что на уровне AST очень сложно обернуть ноду в “нечто”, не изменив при этом логику исполнения. Да и в целом, далеко не все ноды можно обернуть. Этот метод тоже подходит.

Но можно использовать и другой подход. Что если, во время импорта перехватить контроль, обойти байткод импортируемого модуля, добавить внутрь байткода вызов своей функции трассировки, собрать code-object и посмотрим, что получилось. Именно эта идея реализована в прототипе библиотеки OpTrace.

Как работает OpTrace

Прежде всего нужно установить Import.Hook— здесь все довольно просто. В нем есть Finder, который пропускает неинтересные нам модули, создав для нужных Loader. В свою очередь, этот класс получает байт-код модуля, строки его исходного кода, модифицирует байт-код и возвращает измененный байткод в качестве импортируемого модуля.

Работает все это так. Создается wrapper, внутри которого «пробрасываются» две функции — первая нужна для того, чтобы отметить опкод, как уже посещенный (visitor). Задача второй — просто отметить, что такой опкод существует в исходнике (marker).

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

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

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

Подобное представление удобно просматривать, но не обрабатывать. Существует и другой метод — get_instructions. Он принимает на вход code-object и возвращает список инструкций.

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

На этом методе и строится работы прототипа библиотеки. С помощью этого метода обходится весь байткод. Чтобы отметить существование опкода вызывается проброшенная ранее функция marker.

С трассировкой дело обстоит несколько сложнее. Нельзя просто так взять и поместить в байткод вызов каких-то нужных нам методов. У CodeObject есть атрибут consts — это доступные внутри него константы. В них можно поместить lambda-функцию и “замкнуть” в нее текущую инструкцию в качестве параметра по-умолчанию. Таким образом, вызвав эту лямбду из констант без параметров, мы сможем трассировать выполнение конкретных опкодов. Далее нужно лишь сгенерировать код для вызова константы.

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

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

Болдом на скриншоте подсвечен оригинальный трассируемый байткод. После модификации байткода необходимо запустить тесты. Так мы выясним, какая часть кода выполнялась, а какая нет. Возникает вопрос, а что делать с непокрытыми опкодами? В проекте на 50 000 строк их перечисление может занять несколько страниц.

На самом деле способа однозначно перевести любой опкод к строке кода не существует, но можно попытаться его найти. У некоторых опкодов есть информация о строке, в которой они находятся. Значит при обходе мы можем сохранять текущую строку — до момента пока не встретим упоминания другой строки будем считать, что строка не менялась. Именно эта информация будет включаться в отчет. Теперь он выглядит гораздо лучше, уже понятно что и где произошло.

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

Допустим, что строки у нас всегда вычисляются корректно. Теперь можно попробовать вычислить позицию в строке для каждого пропущенного опкода. Рассмотрим несложный пример с опкодом LOAD_FAST. Его параметры говорят о том, что мы имеем дело с загрузкой некоей переменной. Мы можем попробовать в известной нам строке найти ее имя.

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

Покрыв примерно 70 типов опкодов удалось получить вменяемый отчет. Но многие опкоды покрыть невозможно. Новый отчет выглядит так:

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

Удивительно, но это работает. Например, мы четко видим, что не сработал LOAD_FAST для переменной c.

OpTrace: минусы и плюсы

При работе с прототипом имеется ряд проблем.

Заключение

Одной из целей этого исследования и разработки была демонстрация факта того, что не существует идеальных библиотек. Coverage.py хорош, но не идеален — слепо верить его отчетам нельзя. Поэтому необходимо всегда разбираться с тем, как работает библиотека и изучать как она работает “изнутри”.

Еще один ключевой тезис — coverage в 100% расслабляет команду. Раз результатам работы библиотек нельзя полностью доверять, то полное покрытие — это просто ачивка, за которой могут скрываться реальные проблемы.

Источник

Оценка тестового покрытия на проекте

Самый лучший способ оценить, хорошо ли мы протестировали продукт – проанализировать пропущенные дефекты. Те, с которыми столкнулись наши пользователи, внедренцы, бизнес. По ним можно многое оценить: что мы проверили недостаточно тщательно, каким областям продукта стоит уделить больше внимания, какой вообще процент пропусков и какова динамика его изменений. С этой метрикой (пожалуй, самой распространённой в тестировании) всё хорошо, но… Когда мы выпустили продукт, и узнали о пропущенных ошибках, может быть уже слишком поздно: на “хабре” появилась про нас гневная статья, конкуренты стремительно распространяют критику, клиенты потеряли к нам доверие, руководство недовольно.

Чтобы такого не происходило, мы обычно заранее, до релиза, стараемся оценивать качество тестирования: насколько хорошо и тщательно мы проверяем продукт? Каким областям не хватает внимания, где основные риски, какой прогресс? И чтобы ответить на все эти вопросы, мы оцениваем тестовое покрытие.

Зачем оценивать?

Как оценивать?

Прежде, чем внедрять любую метрику, важно определиться, как вы её будете использовать. Начните с ответа именно на этот вопрос – скорее всего, вы сразу поймёте, как её лучше всего считать. А я только поделюсь в этой статье некоторыми примерами и своим опытом, как это можно сделать. Не для того, чтобы слепо копировать решения – а для того, чтобы ваша фантазия опиралась на этот опыт, продумывая идеально подходящее именно вам решение.

Оцениваем покрытие требований тестами

Допустим, у вас в команде есть аналитики, и они не зря тратят своё рабочее время. По результатам их работы созданы требования в RMS (Requirements Management System) – HP QC, MS TFS, IBM Doors, Jira (с доп. плагинами) и т.д. В эту систему они вносят требования, соответствующие требованиям к требованиям (простите за тавтологию). Эти требования атомарны, трассируемы, конкретны… В общем, идеальные условия для тестирования. Что мы можем сделать в таком случае? При использовании скриптового подхода – связывать требования и тесты. Ведём в той же системе тесты, делаем связку требование-тест, и в любой момент можем посмотреть отчёт, по каким требованиям тесты есть, по каким – нет, когда эти тесты были пройдены, и с каким результатом.
Получаем карту покрытия, все непокрытые требования покрываем, все счастливы и довольны, ошибок не пропускаем…

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

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

Проблема: требования не атомарны.

Аналитики тоже иногда грешат винегретом в голове, и обычно это чревато проблемами со всем проектом. Например, вы разрабатываете текстовый редактор, и у вас могут быть в системе (в числе прочих) заведены два требования: «должно поддерживаться html-форматирование» и «при открытии файла неподдерживаемого формата, должно появляться всплывающее окно с вопросом». Сколько тестов требуется для базовой проверки 1-го требования? А для 2-го? Разница в ответах, скорее всего, примерно в сто раз. Мы не можем сказать, что при наличии хотя бы 1-го теста по 1-му требованию, этого достаточно – а вот про 2-е, скорее всего, вполне.

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

Конечно, такой процесс согласования требует немало ресурсов и времени, особенно поначалу, до наработки практики. Поэтому проводите по нему только высокоприоритетные требования, и новые доработки. Со временем и остальные требования подтянете, и все будут счастливы! Но… а если требований нет вообще?

Проблема: требований нет вообще.

Они на проекте отсутствуют, обсуждаются устно, каждый делает, что хочет/может и как он понимает. Тестируем так же. Как результат, получаем огромное количество проблем не только в тестировании и разработке, но и изначально некорректной реализации фич – хотели совсем другого! Здесь я могу посоветовать вариант «определите и задокументируйте требования сами», и даже пару раз в своей практике использовала эту стратегию, но в 99% случаев таких ресурсов в команде тестирования нет – так что пойдём значительно менее ресурсоёмким путём:

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

Но… Что делать, если требования ведутся, но не в трассируемом формате?

Проблема: требования не трассируемы.

На проекте есть огромное количество документации, аналитики печатают со скоростью 400 знаков в минуту, у вас есть спецификации, ТЗ, инструкции, справки (чаще всего это происходит по просьбе заказчика), и всё это выступает в роли требований, и на проекте уже все давно запутались, где какую информацию искать?
Повторяем предыдущий раздел, помогая всей команде навести порядок!

Но… Ненадолго… Кажется, за прошлую неделю аналитики по обращениям заказчиков обновили 4 разные спецификации.

Проблема: требования всё время меняются.

Конечно, хорошо бы тестировать некую фиксированную систему, но наши продукты обычно живые. Что-то попросил заказчик, что-то изменилось во внешнем к нашему продукту законодательстве, а где-то аналитики нашли ошибку анализа позапрошлого года… Требования живут своей жизнью! Что же делать?

Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Смотреть картинку Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Картинка про Какой уровень coverage достаточен для утверждения что тестирование проведено качественно. Фото Какой уровень coverage достаточен для утверждения что тестирование проведено качественно

В этом случае мы получаем все бенефиты оценки тестового покрытия, да ещё и в динамике! Все счастливы. Но…
Но вы так много внимания уделяли работе с требованиями, что теперь вам не хватает времени либо на тестирование, либо на документирование тестов. На мой взгляд (и тут есть место религиозному спору!) требования важнее тестов, и уж лучше так! Хотя бы они в порядке, и вся команда в курсе, и разработчики делают именно то, что нужно. НО НА ДОКУМЕНТИРОВАНИЕ ТЕСТОВ ВРЕМЕНИ НЕ ОСТАЁТСЯ!

Проблема: не хватает времени документировать тесты.

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

Но… Какое ещё «но»? Какое.

Говорите, все обойдём, и да пребудут с нами качественные продукты!

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *