что такое покрытие кода тестами

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

Инструмент тестирования 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’

Источник

Тестовое покрытие кода: от мифа к реальности

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

Но времена изменились. Большинство рабочих мест в кабинках исчезло, и программисты начали любить свое ремесло. С появлением Agile-технологий и движением Software Craftsmanship появилось много новых инструментов, помогающих программисту и процессу. TDD постепенно становится де-факто способом написания кода, и секреты SCRUM или Kanban были открыты даже программистам в самых темных уголках мира.

Автоматизированное тестирование и разработка через тестирование (TDD) являются одними из основных методов, которые Agile предоставляет нам, программистам. И инструмент, который поставляется с этими методологиями, используется для создания тестового кода, который является темой этой статьи.

Определение

«В информатике охват кода — это мера, используемая для описания степени, в которой исходный код программы тестируется определенным набором тестов».

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

Информация может быть представлена ​​различными способами, от простого процента до симпатичной графики или даже выделения в реальном времени в вашей любимой IDE.

Давайте проверим это в действии

Мы будем использовать PHP в качестве языка для иллюстрации нашего кода. Кроме того, нам понадобятся PHPUnit и XDebug для тестирования нашего кода и сбора данных покрытия.

Исходный код

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

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

Тестовый код

Мы написали этот код с помощью Test Driven Development (TDD), и у нас есть 100% покрытие кода. Это означает, что, выполняя наш тест, мы проверяем каждую строку исходного кода.

Выполнение тестов в CLI с покрытием только текста

Одним из способов получения данных покрытия является запуск наших тестов в CLI (интерфейс командной строки) и анализ выходных данных. В этом примере мы будем использовать UNIX-подобную операционную систему (Linux, MacOS, FreeBSD и т. Д.). Пользователям Windows нужно будет немного адаптировать пути и имена исполняемых файлов, но это должно быть довольно похоже.

Давайте откроем консоль и изменим каталоги в вашей test папке. Затем запустите phpunit с возможностью генерировать данные покрытия в виде простого текста.

Это должно работать «из коробки» на большинстве систем, если установлен XDebug, однако в некоторых случаях вы можете столкнуться с ошибкой, связанной с часовыми поясами.

И данные покрытия будут в указанном текстовом файле.

Давайте немного разберемся с этим.

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

Генерация вывода покрытия HTML

Просто изменив простой параметр для PHPUnit, мы можем генерировать хороший вывод HTML.

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Покрытие внутри нашей IDE

Предыдущие примеры были интересны и весьма полезны, если ваш код построен на каком-то удаленном сервере, к которому у вас есть только SHH или веб-доступ. Но разве не было бы неплохо иметь всю эту информацию, жить в вашей IDE?

Если вы используете PHPStorm, все в пределах одного клика! Выберите для запуска ваших тестов с покрытием, и вся информация просто будет отображаться волшебным образом.

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Информация о покрытии будет присутствовать в вашей IDE несколькими способами и в нескольких местах:

Мифы о покрытии кода

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

Иногда программисты склонны думать, что код с 100% покрытием не содержит ошибок. Еще один миф Покрытие кода просто говорит вам, что вы протестировали каждую строку кода. Это мера количества используемых линий. Это не мера количества правильно реализованных строк. Например, наполовину написанные алгоритмы с только половиной определенных тестов будут по-прежнему иметь 100% охват. Это не означает, что алгоритм завершен или что он работает правильно.

Наконец, игровая система очень проста. Конечно, если вы используете TDD, вы, естественно, имеете высокую стоимость покрытия. На целых проектах 100% невозможно. Но на небольших модулях или классах получить 100% покрытие очень просто. Возьмите, к примеру, наш исходный код и представьте, что у вас вообще нет тестов. Что будет самым простым тестом для выполнения всего кода?

Источник

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

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

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

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

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

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

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

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

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

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

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

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

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

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

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

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

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

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

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

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

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

Источник

Покрытие кода

Что такое покрытие кода?

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

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

В этом уроке вы узнаете

Зачем использовать покрытие кода?

Вот несколько основных причин использования покрытия кода:

Методы покрытия кода

Ниже приведены основные методы покрытия кода.

Заявление покрытия

Что такое покрытие заявления?

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

Охват операторов используется для выведения сценария на основе структуры тестируемого кода.

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

Давайте разберемся с этим на примере, как рассчитать покрытие выписки.

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

Исходный код:

Сценарий 1:

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Операторы, отмеченные желтым цветом, — это те операторы, которые выполняются в соответствии со сценарием.

Количество выполненных выписок = 5, Общее количество выписок = 7

Охват выписки: 5/7 = 71%

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Аналогично мы увидим сценарий 2,

Сценарий 2:

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Операторы, отмеченные желтым цветом, — это те операторы, которые выполняются согласно сценарию.

Количество выполненных заявлений = 6

Общее количество заявлений = 7

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Охват выписки: 6/7 = 85%

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Но в целом, если вы видите, все утверждения охватываются 2- м сценарием. Таким образом, мы можем сделать вывод, что общий охват отчетности составляет 100%.

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Что входит в покрытие заявления?

Охват решений

Об охвате решений сообщается об истинных или ложных результатах каждого логического выражения. В этом покрытии выражения могут иногда усложняться. Поэтому очень сложно достичь 100% покрытия.

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Пример покрытия решения

Рассмотрим следующий код:

Сценарий 1:

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Код, выделенный желтым цветом, будет выполнен. Здесь «Нет» результат решения If (a> 5) проверяется.

Сценарий 2:

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Код, выделенный желтым цветом, будет выполнен. Здесь «Да» результат решения Если (а> 5) проверяется.

ПрецедентЗначение АВыводОхват решений
12250%
261850%

Охват филиала

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

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

Используя метод покрытия Branch, вы также можете измерить долю независимых сегментов кода. Это также поможет вам узнать, какие разделы кода не имеют ветвей.

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Пример покрытия филиала

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

Рассмотрим следующий код

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Покрытие филиала также будет учитывать безусловное отделение

ПрецедентЗначение АВыводОхват решенийОхват филиала
12250% 33%
261850% 67%

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

Тестирование покрытия филиала предлагает следующие преимущества:

Состояние покрытия

Условное покрытие или покрытие выражений покажет, как оцениваются переменные или подвыражения в условном выражении. В этом покрытии рассматриваются только выражения с логическими операндами.

Например, если в выражении есть логические операции, такие как AND, OR, XOR, которые указывают общие возможности.

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

Формула для расчета покрытия условий:

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Для приведенного выше выражения у нас есть 4 возможных комбинации

Рассмотрим следующий вход

Состояние покрытия = 25%

Покрытие конечного автомата

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

Какой тип покрытия кода выбрать

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

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

Покрытие кода против функционального покрытия

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

Инструменты покрытия кода

Вот список важных инструментов покрытия кода:

Источник

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

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

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

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

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

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

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

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

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

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

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

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

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

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

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

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

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

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

Допустим, мы хотим покрыть его и знать, когда не срабатывало условие “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).

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

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

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

что такое покрытие кода тестами. Смотреть фото что такое покрытие кода тестами. Смотреть картинку что такое покрытие кода тестами. Картинка про что такое покрытие кода тестами. Фото что такое покрытие кода тестами

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

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

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

Заключение

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

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

Источник

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

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