Перейти к содержимому

Фотография

Unit Testing


  • Авторизуйтесь для ответа в теме
Сообщений в теме: 3

#1 Green

Green

    Профессионал

  • Members
  • PipPipPipPipPipPip
  • 1 233 сообщений
  • ФИО:Гринкевич Сергей
  • Город:Москва

Отправлено 07 сентября 2004 - 13:04

Может ли кто-нибудь поделиться опытом организации процесса Юнит тестирования в компании?

В первую очередь интересует проблема контроля полноты покрытия тестами написанного кода.
Есть ли какие-нибудь формальные решения или рекомендации на этот счет?

Основная идея может быть сформулирована следующим образом:
If we can measure it we can control it.

Спасибо.
  • 1
Гринкевич Сергей

#2 barancev

barancev

    Администратор

  • Admin
  • PipPipPipPipPipPip
  • 6 872 сообщений
  • ФИО:Алексей Баранцев
  • Город:Россия, Москва


Отправлено 08 сентября 2004 - 13:32

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

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

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

Но если какие-то части системы разработаны вручную и так же вручную сопровождаются, имеет смысл для таких частей сделать систему тестов, дающую высокое покрытие кода (~90-100%). Добиваться полного покрытия или нет - это обычный вопрос анализа рисков. Нужно смотреть непокрытый код и оценивать, сколько будет стоить разработка тестов и сколько убытков получится, если вдруг там всё-таки окажется ошибка и с какой вероятностью это произойдёт.

Является ли покрытие кода достаточно хорошей метрикой для ценки качества?

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

1) Насколько хороши тесты, при выполнении которых измерялось покрытие - может быть они просто гоняли систему в разных режимах, но не выполняли никаких проверок правильности работы, то есть проверяли только то, что она "не падает". Надо как-то оценить качество тестов.

2) Все ли требования тестировались, возможно некоторые требования не реализованы, но и тестов для них нет, все счастливы, покрытие 100%, только заказчик будет недоволен. Надо измерять ещё и покрытие тестами требований.

Тепрь наоборот, представим, что полного покрытия кода достичь не удаётся, хотя требования покрыты на 100%. Что это может означать?

1) Есть "мёртвый", то есть недостижимый, код. Нужно ли его удалять? А вруг он не совсем "мёртвый", просто требования неправильные (и основанные на них тесты, следовательно, тоже). Опять - анализируйте риски.

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

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

Измерить можно, и контролировать можно, даже управлять можно покрытием кода. Вопрос только в том, какое отношение всё это имеет к качеству продукта в целом?
  • 0
Алексей Баранцев
Тренинги для тестировщиков (тестирование производительности, защищенности, тест-дизайн, автоматизация):
Линейка тренингов по Selenium

#3 Green

Green

    Профессионал

  • Members
  • PipPipPipPipPipPip
  • 1 233 сообщений
  • ФИО:Гринкевич Сергей
  • Город:Москва

Отправлено 08 сентября 2004 - 15:54

Спасибо за развернутый ответ.
Попробую несколько сузить вопрос.

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

Как проводить юнит тестирование - не вопрос. Имеются знания, опыт и квалифицированные специалисты.

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

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

Существует ли готовый механизм, позволяющий получать такую статистику?
  • 0
Гринкевич Сергей

#4 barancev

barancev

    Администратор

  • Admin
  • PipPipPipPipPipPip
  • 6 872 сообщений
  • ФИО:Алексей Баранцев
  • Город:Россия, Москва


Отправлено 09 сентября 2004 - 07:47

Спасибо за развернутый ответ.
Попробую несколько сузить вопрос.

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

Это, конечно, не имеет непосредственного отношения к тестированию, и даже отклоняется от темы оригинального вопроса, но всё равно прокомментирую. Инспекция кода -- дело хорошее и при правильном подходе может быть организована для команд практически неограниченного размера. Знаю реальные примеры. Если у кого есть желание обсудить такую форму повышения качества кода -- в отдельную тему.

Как проводить юнит тестирование - не вопрос. Имеются знания, опыт и квалифицированные специалисты.

Это точно, как проводить -- не вопрос. Вопрос -- зачем проводить B)
Я уже писал однажды, что вопрос "как?" скучный, все знают на него ответ и даже не один. Интересный вопрос -- "зачем?"

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

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

Существует ли готовый механизм, позволяющий получать такую статистику?

По-моему, ответ почти очевиден, и Вы его ожидали, хотя и боялись услышать: В ОБЩЕМ СЛУЧАЕ НЕТ.

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

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

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

1. Классический учебный пример: функция извлечения квадратного корня. На входе вещественное число, на выходе тоже. Внутри -- реализация, скажем, методом последовательных приближений. Вопрос: сколько нужно тестов? Ответ: зависит от требований (!!!).

Во-первых, конечно же без всяких требований ясно, что нужно провести разбиение области определения на классы эквивалентности. Но как это сделать? Простейший способ: отрицательные числа, ноль, положительные числа. Такие три теста вполне могут дать полное покрытие кода. И тут-то начинается самое интересное. Заглядываем в требования. Оказывается, функция должна вычислять результат с заданной точностью, причём эта точность на разных участках области определения различна (увы, машинное представление вещественных чисел далеко от математически чистого идеала). Приходится измельчать разбиение на классы эквивалентности в соответствии с требованиями. Далее, в требованиях описано, как функция должна реагировать на специальные значения -- нули (+0, -0), бесконечность (+inf, -inf), неопределённость (NaN), а в коде нигде нет явной реализации работы с такими значениями, потому что алгоритм неявно справляется с такими проблемами. Но тестировать всё равно надо. Но и это ещё не всё -- в дополнение к требованиям приложено замечание от разработчиков, что для реализации использован такой-то алгоритм, описанный в такой-то книге. Заглядываем в книгу и видим, что там есть некоторые условия на сходимость алгоритма. Опа! И это тоже нужно тестировать, хотя тесты и получаются реализационно-зависимыми и после изменения алгоритма нужно будет их менять. В итоге получаем не три теста, а тридцать три, хотя для покрытия кода достаточно было бы трёх.

2. Другой пример: парсер XML (бывают языки гораздо хуже, я выбрал самый простой :)). Одна интерфейсная функция, на входе строка, на выходе -- дерево разбора, DOM. Вопрос: сколько нужно тестов? Тут в код вообще хоть засмотрись -- ни в жизнь не догадаешься, как его покрыть.

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

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

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

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

Напоследок я Вам всё-таки ещё раз посоветую задуматься над тем, зачем юнит-тестирование? Покрыть код -- это не та цель, к которой нужно стремиться.
  • 0
Алексей Баранцев
Тренинги для тестировщиков (тестирование производительности, защищенности, тест-дизайн, автоматизация):
Линейка тренингов по Selenium


Количество пользователей, читающих эту тему: 0

0 пользователей, 0 гостей, 0 анонимных