Как сделать содержательный анализ покрытия кода моих юнит-тестов? - PullRequest
5 голосов
/ 17 июня 2009

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

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

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

Так, как я могу провести такой анализ. Какие инструменты мне доступны?

Я использую Python 2.4 на Windows 32bit XP

UPDATE0:

Просто чтобы уточнить: у нас есть очень полный набор модульных тестов (плюс отдельный и очень полный набор тестов, который выходит за рамки этого упражнения). У нас также есть очень стабильная платформа непрерывной интеграции (построенная на базе Hudson), которая предназначена для разделения и выполнения стандартных юнит-тестов python на нашем испытательном стенде: около 20 ПК, созданных по спецификации компании.

Цель этого упражнения - заполнить все пробелы в нашем наборе (только) для пакета юнитов python, чтобы каждый компонент имел некоторую степень покрытия юнит-тестами. Другие разработчики будут нести ответственность за компоненты проекта, не относящиеся к Python (которые также находятся вне области видимости).

" Component " намеренно расплывчато: иногда это будет класс, а иногда - целый модуль или сборка модулей. Это может даже относиться к единой финансовой концепции (например, к одному типу финансового опциона или финансовой модели, используемой многими типами опционов). Этот торт можно разрезать разными способами.

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

Ответы [ 5 ]

6 голосов
/ 17 июня 2009

Только для покрытия кода вы можете использовать cover.py .

Что касается cover.py против figleaf :

фиговый листок отличается от золотого стандарта инструментов покрытия Python ('lighting.py') несколькими способами. Прежде всего, Figleaf использует тот же критерий для "интересных" линий кода в качестве функции sys.settrace, которая устраняет некоторые сложности в cover.py (но это означает, что ваш счет "loc" уменьшается). Во-вторых, figleaf не записывает выполненный код в стандартной библиотеке Python, которая приводит к значительному ускорению. А также в-третьих, формат, в котором Формат покрытия сохраняется очень с ним легко и просто работать.

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

Полагаю, у обоих есть свои плюсы и минусы.

4 голосов
/ 17 июня 2009

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

  • Каждый пакет Python имеет UnitTests .
  • Мы автоматически обнаруживаем модульные тесты, используя перенос . Нос автоматически обнаруживает стандартные модульные тесты Python (в основном все, что выглядит как тест ). Тем самым мы не пропускаем юнит-тесты. Нос также имеет концепцию плагинов, чтобы вы могли производить, например, хороший вывод.
  • Мы стремимся к 100% охвату модульное тестирование. Для этого мы используем покрытие проверить, потому что плагин-носитель обеспечивает интеграцию .
  • Мы настроили Eclipse (нашу IDE) на , который автоматически запускает программу каждый раз, когда файл изменяется, так что модульные тесты всегда выполняются, что показывает покрытие кода как побочный продукт.
4 голосов
/ 17 июня 2009

Первым шагом будет написание значимых тестов. Если вы будете писать тесты, предназначенные только для полного охвата, вы будете контрпродуктивны; это, вероятно, будет означать, что вы сосредоточитесь на деталях реализации подразделения, а не на его ожиданиях.

Кстати, я бы использовал нос в качестве фреймворка unittest (http://somethingaboutorange.com/mrl/projects/nose/0.11.1/); это система плагинов очень хороша и оставляет вам возможность покрытия (--with-cover для покрытия Неда, --with-figleaf для Titus one ; поддержка покрытия3 должна появиться), и вы также можете написать плагин для своей собственной системы сборки.

3 голосов
/ 17 июня 2009

«В каждой части нашего проекта имеется значимый тест»

«Часть» не определена. «Значимый» не определен. Впрочем, это нормально, так как в дальнейшем это становится лучше.

"подтверждает правильность каждого компонента в нашей системе"

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

  • Проверяет правильность каждого модуля.

  • Проверяет правильность каждого класса каждого модуля.

  • Проверяет правильность каждого метода каждого класса каждого модуля.

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

«гарантирует, что при изменении чего-либо мы можем обнаружить непреднамеренные изменения в других подсистемах»

Это регрессионное тестирование. Это логическое следствие любой дисциплины модульного тестирования.

Вот что вы можете сделать.

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

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

  3. Приоритет ваших модулей. Хорошее правило «наиболее часто используется». Другое правило - «наибольший риск неудачи». Другое правило - «большинство сообщений об ошибках». Это займет несколько часов.

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

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

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

  • Новая разработка. Для каждого изменения кода необходимо создать unittest.TestCase для изменяемого класса.

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

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

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

1 голос
/ 17 июня 2009

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

  • Для модульных тестов Python

  • Для кода C это сложно на многих платформах, потому что gprof, профилировщик кода Gnu, не может обрабатывать код, созданный с -fPIC. Таким образом, в этом случае вы должны строить каждое расширение статически, что не поддерживается многими расширениями (см. Мой пост в блоге для numpy , например). В Windows могут быть более эффективные инструменты покрытия кода для скомпилированного кода, но для этого может потребоваться перекомпилировать расширения с помощью компиляторов MS.

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

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