2. • Visual Studio 2008
• SQL Server
• Perforce
• Microsoft Hyper-V Server 2008
• Cruise Control.NET
• .NET Framework 3.5
•12500 строк кода на языке С#
• 4000 строк модульных тестов
• 111000 строк скриптов базы данных
• 47000 строк функциональных тестов
• Время запуска всех тестов более 4.5
часов
• 4-6 чел. команда разработки
Что мы имеем сейчас
3. 1) Модульное тестирование
2) Функциональное тестирование
3) Стратегия работы с контролем версий
4) Тестирование конфигураций
5) Распределенные тесты
6) Сервер непрерывной интеграции
Этапы постановки процесса тестирования
4. • Я знаю, как работает моя программа.
• Ошибки выявляются при отладке.
• С ростом объема кода растет время отладки.
Начинаем проект!
Нам тесты не нужны!
5. Модульные тесты, если…
• Проверка отдельных частей.
• Покрытие кода.
• Меньше ошибок
Низкое качество, частые ошибки!
Много времени уходит на отладку!
7. Этапы постановки процесса тестирования
1) Модульное тестирование
2) Функциональное тестирование
3) Стратегия работы с контролем версий
4) Тестирование конфигураций
5) Распределенные тесты
6) Сервер непрерывной интеграции
8. Функциональные тесты, если…
• Тестирование черного ящика.
• Тестировщиков нет
• Visual Studio generic test.
• План тестирования.
Неизвестно какие функции
Работают, а какие нет
Неизвестно
взаимовлияние функций
Невозможно быстро протестировать
систему в целом
9. Что мы получили
• Вносить изменения легко.
• Минимальная отладка.
• Регрессионное тестирование.
• Выпуск релиза.
10. Этапы постановки процесса тестирования
1) Модульное тестирование
2) Функциональное тестирование
3) Стратегия работы с контролем версий
4) Тестирование конфигураций
5) Распределенные тесты
6) Сервер непрерывной интеграции
11. Стратегия работы с контролем версий, если…
• Вносить изменения легко.
• Минимальная отладка
• Выпуск релиза mainline
feature 1
feature 2
release v.1.0
Разработчики мешают друг другу!
Тестировать постоянно меняющуюся
версию невозможно!
12. Этапы постановки процесса тестирования
1) Модульное тестирование
2) Функциональное тестирование
3) Стратегия работы с контролем версий
4) Тестирование конфигураций
5) Распределенные тесты
6) Сервер непрерывной интеграции
13. Заказчики хотят разного!
• Вносить изменения легко.
• Минимальная отладка
• Выпуск релиза
F1
F2
F3
F2*
F3*
15. Этапы постановки процесса тестирования
1) Модульное тестирование
2) Функциональное тестирование
3) Стратегия работы с контролем версий
4) Тестирование конфигураций
5) Распределенные тесты
6) Сервер непрерывной интеграции
16. Запуск тестов
• Тестов много.
• Запуск парализует остальную работу.
• Редко запускаются.
• Больше тестов в красной зоне.
Тест 1
Тест 2
Тест 3
Тест 4
Тест N
Проблема: Тесты выполняются слишком долго!
17. Распределенные тесты, если…
Вирт. машина 1
Тест 1
Тест 2
Вирт. машина 2
Тест 3
Тест 4
Вирт. машина 3
Тест N-1
Тест N
Тесты выполняются слишком долго!
18. Этапы постановки процесса тестирования
1) Модульное тестирование
2) Функциональное тестирование
3) Стратегия работы с контролем версий
4) Тестирование конфигураций
5) Распределенные тесты
6) Сервер непрерывной интеграции
19. Проблемы, которые решает
сервер непрерывной интеграции
Много ручной работы!
Разработчики игнорируют
запуск тестов!
Проблема растет
как снежный ком!
20. Как работает сервер непрерывной интеграции
Сервер сборки
Сервер непрерывной интеграции
Цикл сборки Отчеты
ЛогированиеВнешние приложения
ГруппаТриггер
21. Серверы непрерывной интеграции обслуживают
все ветки разработки
• Вносить изменения легко.
• Минимальная отладка
• Выпуск релиза mainline
feature 1
feature 2
release v.1.0
Сервер №1
Сервер №2
Сервер №4
Сервер №3
22. • основная группа из 1000 тестов проходят за 5 минут.
• Автоматическая сборка.
• Результаты тестов сразу.
• Тяжелые тесты по расписанию (ночью).
• Каждую ветку разработки обслуживает отдельный сервер интеграции
Чего мы достигли
Здравствуйте, меня зовут Артем Шабаршин. Я работаю в компании иствинд. Наша компания разрабатывает решения для телекоммуникационной отрасли (например для сотовых компаний, таких как Skylink, СМАРТС, Уралсвязьинформ). Я участвую в разработке модуля тарификации услуг связи. Тарификация «Все по рублю» или «Каждая вторая минута бесплатно» это и есть наша работа Ну или чуть сложнее – например бонусные баллы и пакеты минут или мегабайт. Этот модуль состоит из программы, написанной на языке c# и базевой части. Свой доклад я хочу начать с вопроса:
Поднимите руки, кто занимается профессиональной разработкой, а кто работает в тестировании, а кто еще студент?
Что мы имеем сейчас. Сам модуль тарификации разрабатывается на языке C#, используются возможности .NET framework 3.5. Базевая часть работает под управлением sql server. Система контроля версий – Perforce. Microsoft Hyper-V Server 2008 это виртуальная среда, в которой работают виртуальные машины, на которых запускаются тесты. В качестве сервера непрерывной интеграции мы используем Cruise Control.NET. Теперь немного цифр….
Сейчас, глядя назад, я могу сказать что мы прошли следующие этапы становления процесса функционального тестирования. Модульные тесты, функциональные тесты, стратегия работы с контролем версий, распределенные тесты, сервер непрерывной интеграции. Все эти пункты мы с вами рассмотрим более подробно.
Перед тем как я начну я хочу чтобы вы представили себе начинающую команду, которая не ставит себе цели иметь вообще какое-либо тестирование. Команда, которая хочет сделать качественный продукт, и отвечает на возникающие в связи с этим вызовы по мере продвижения к цели. В мое докладе я не преследую цель рассказать как нужно, делать
или как вы должны делать. Наш пример не является самым успешным и наоборот не является самым неудачным. Это скорее реальная историю о том как это бывает
в большинстве компаний (в которые вы придете – если там студенты). Надеюсь что кому-то это будет полезно.
С чего мы начинали: 5 лет назад, когда мы начинали работу над проектом мы не применяли тестирование вообще. Мы даже не задумывались о том, нужно оно нам или нет. Мы считали что хорошо понимаем и знаем как будет работать наша программа. Процесс был такой: мы писали код, запускали приложение и подавали на вход начальные данные, затем мы смотрели что у нас там получалось. Если результат был не тем, который мы ожидали. Приходилось запускать в отладчике нашу программу и пытаться найти ошибку. С ростом объема кода время затрачиваемое на локализацию ошибок и их устранение увеличивалось. У нас появилась проблема: внесение изменений приводит к ошибкам, которые долго локализуются. Назревала проблема с качеством программы, она просто постоянно ломалась. И нас это серьзно беспокоило. Мы собрались и начали думать, что мы можем предпринять.
Что бы вы могли предложить для решения этой проблемы?
Мы решили попробовать «автоматизированное тестирование»
И так тестирования у нас не было. На самом первом этапе мы цели никакой не ставили. А лишь понимали что нам что-то нужно поменять, что бы изменить качество нашей программы. Самое первое что пришло в голову это использовать модульные тесты. Модульные тесты проверяют отдельные части разрабатываемой системы, но не проверяются как эти части взаимодействуют между собой. Каждый модульный тест как бы покрывает строки боевого кода. На слайде мы видим что в результате выполнения тестов программа выполнялась по веткам, раскрашенным в зеленый цвет и не проходила по веткам раскрашенным в красный. Соотношение покрытых тестами веток к непокрытым называют – Покрытие кода. Измеряется оно в процентах. Обычно один или несколько модульных тестов проверяют один метод класса. Мы покрыли нашу систему тестами на 80%. И ошибки стали происходить реже.
Если у вас уже есть какая-то разрабатываемая система, но нет тестов, то я вам рекомендую как можно раньше начать писать тесты, а при дальнейшей разработке применять подход, который называется тест дривен девелопмент или разработка от тестирования. Он заключается в том, что бы до написание кода, вы составили тест, который проверяет этот код, далее вы пишете код таким образом, чтобы он удовлетворял тесту, потом вы меняете тест, так, чтобы он удовлетворял новым требованиям, исправляете код. При таком способе разработке каждый новый тест должен попадать в красную зону, т.е. не проходить, после того как проверяемый код удовлетворяет требованиям теста, тест попадает в зеленую зону – т.е. он проходит. После этого вам необходимо провести рефакторинг. Под рефакторингом понимается процесс изменения кода, но без изменения функциональности, Он нужен для устранения дублирования кода, повышения его удобочитаемости. В противном случае ваш код будет избыточным и трудночитаемым.
Как я говорил модульные тесты сняли часть проблемы. Программа стала ломаться гораздо реже и на какое-то время мы успокоились. Мы применяли подход TDD.
Но затем нас ждала следующая проблема. Новые функциональные требования появлялись очень часто и это приводило к тому, что написав функцию №10 часть написанных ранее функций переставала работать. Т.е. начали проявляться зависимости в системе. В какой-то момент мы снова поняли что не контролируем ситуацию,
Мы не могли гарантировать что все система в определенный момент времени удовлетворяла ВСЕМ без исключения функциональным требованиям.
И решили мы использовать функциональные тесты. Функциональное тестирование это тестирование черного ящика и это область ответственности тестировщиков. В нашей компании группа тестирования работала на тот момент над другими продуктами и им просто не хватало времени на нас. Поэтому нам пришлось это взять на себя. Нами были рассмотрены несколько инструментов для тестирования, и мы остановились на решениях от майкрософт. Мы попробовали TFS, но пока мы его использовать не можем из-за того что у него своя система контроля версий, а вся наша компания наботает на перфорсе и это не так просто всю компанию перевести на TFS. И так мы решили остановиться на возможностях, имеющихся в Visual Studio. Для этого мы дополнительно написали движок тестирования который читает план тестирования, написанный на xml и выполняет его и мы воспользовались такой штукой как Visual Studio generic test, который запускает наш движок и подсовывает ему план тестирования. В плане тестирования у нас есть.
Есть свой минимально необходимый язык сценария теста, реализованный но основе XML.
И так у нас есть модульное и функциональное тестирование. Какие плюсы мы получили. Вносить изменения легко. Мы не боимся изменять существующий код, так как тесты покажут, что где мы испортили. В следствии этого время на отладку у нас резко уменьшилось. Если вы изменяете какую-то часть вашей системы, вы после этого запускаете все тесты и смотрите как это повлияло на другие части системы, такой подход называется регрессионным тестированием. После этого этапа у нас вышел первый релиз нашей программы, т.к. уже не нужно было беспокоится о том, что какая-то функция работает неправильно или вовсе не работает.
Пока мы разрабатывали программу, вопроса о том как именно пользоваться системой контроля версий не вставало.
Выглядело это так, что все совместно владели кодом и пользовались одной веткой в системе контроля версий.
Правил не было. Любой разработчик мог сохранить не компилирующийся код, код для которого не выполняются тесты.
Никаких правил когда запускать тесты, когда проводить компиляцию не было.
Назревала проблема, т.к. во-первых нужно было получить стабильную версию для установки заказчику. Во-вторых нужно было
оперативно исправлять ошибки в установленной системе, при этом параллельно разрабатывать несколько новых функций.
Все это имеет непосредственное отношение к тестированию, т.к. для разных задач необходимо запускать разные наборы тестов,
и тестировать программу в то или иное время. Например версия установленная у заказчика всегда должна компилироваться и должны проходить
Абсолютно все тесты. К этой версии предъявляются самые жесткие требования. А версия, в которой я разрабатываю новую функцию,
Может вообще не компилироваться. Кроме прочего в одной ветке все постоянно мешали друг другу.
Поднимите руки те, кто имеет опыт работы с системой контроля версий. Система контроля версий позволяет группе разработчиков совместно владеть кодом. Каждый разработчик на своей машине пишет исходные тексты и сохраняет их на сервере контроля версий. Этот процесс называется сабмит или чекин, в зависимости от продукта, который вы используете. В дальнейшем он может получать последние версии файлов проекта и работать с тем, что разработали его коллеги. Если один и тот же файл изменялся несколькими разработчиками, то при сохранении в контроль версий происходит процесс устранения конфликтов (resolve). Важным свойством системы контроля версий является то, что можно всегда узнать кто какое изменение внес в программу. Можно откатиться на более старую ревизию программы, если мы решали что-то попробовать но у нас не получилась наша затее и мы от нее решили отказаться. Как нам может это помочь для тестирования. Однажды при разработке новой функции я столкнулся с тем, что другой разработчик тоже вносил изменения и после того, как я взял последнюю версию программы у меня упали почти все тесты, т.к. наши с ним изменения конфликтовали друг с другом. В итоге нам пришлось сидеть вместе и разбираться что мы наделали. Если вы разрабатываете в своей команде несколько относительно независимых функциональностей одновременно, вам необходимо использовать ветвление и слияние. Ветвление это создание параллельной ветки разработки, которая представляется как точно такая же рабочая папка разработки, вы в этой папке пишете новые функции и тестируете их, другие разработчики сидят в своих ветках и вы не мешаете друг другу. После этого как вы заканчиваете свои изменения вы производите слияние вашей ветки с основной, устраняете все конфликты и после этого производите слияние с другими ветками разработки. Этот процесс может быть трудным и вам возможно придется задействовать участников этой группы.
Если в релизе вы обнаружили дефект, то вы исправляете его, предварительно написав тест его обнаружения и производите слияние с основной веткой и с ветками разработки, которые на данном этапе являются действующими.
Мы воспользовались мировым опытом работы с контролем версий и придерживаемся следующей стратегии работы с контролем версий.
В основной ветке разработки у нас всегда код находится в рабочем состоянии и все тесты проходят.
В ветках разработки код компилируется, но тесты могут не проходить
Перед слиянием должны проходить все тесты.
После слияния прогоняются все тесты, т.к. есть правила для основной ветки разработки.
Из основной ветки можно выпускать релизы и собирать проекты для группы тестирования.
Таким образом определяя стратегию работы с контролем версий вы откладываете возможные конфликты в тестах на последний момент.
С точки зрения тестирования важно, что в разных ветках разные требования к тестированию.
В ветке feature тесты могу не проходить но код компилируется
Но перед слиянием все тесты должны проходить
В ветке Release самые жестки требования, перед сабмитом прогоняется ВСЕ
В Ветке mainline аналогично Release
И важно, что для разных веток запускаются разные группы тестов, например для feature запускается только базовый набор тестов, тесты производительности и интеграционные не запускаются.
После внедрения правил использования репозитория на какое-то время снова все стало спокойно, пока не появился второй и третий заказчики.
В нашей отрасли важной частью дохода является доработка продукта по индивидуальные требования закачика. Т.е. продукт не совсем
Коробочный. Примерно 5-10% системы обычно дорабатывается индивидуально. На самом деле это немного пробелматично, т.к. удобно
иметь полностью коробочный продукт, такой как например ICQ. Или иметь полностью кастомизированное решение, заказную разработку.
Но не тот ни другой вариант нам полностью не подходил.
Заказчики бывают разными. Есть вот такие а есть такие и есть наконец такие. Наш первый релиз для первого заказчика выполнял условно функции ф1, ф2, ф3. Когда мы решили ставиться у двух других заказчиков, то выяснилось, что им не нужны функции ф2 и ф3, а нужны слегка модифицированные версии. Что мы могли в это случае поделать. Сначала мы рассмотрели вариант создания отдельных версий программ для этих заказчиков, но нам не понравилось то, что мы должны будем поддерживать и развивать параллельно три версии программы и три набора тестов. Лучше всего в такой ситуации попытаться оставить одну программу - коробочный продукт и ввести конфигурации клиентов. В которых определялось бы какие функции необходимо использовать. Перед нами встала задача – а как проанализировать чем клиенты отличаются друг от друга и как это записать. Вот что вам необходимо использовать.
Мы нарисовали таблицу в которой в столбцах записаны наши заказчики а в строка функциональности которые есть в нашей программе. В ячейках мы записываем как эти функциональности должны выглядеть у того или иного клиента. Зачем это нужно? Мы видим общую картину того, как та или иная функция может изменяться у разных клиентов. Это позволяет принимать правильные решения при проектировании новых функций. Например видя что F3 меняется мы должны предусмотреть механизм подмены этой функции и добавить возможность определять какая функция нужна на основании записи в конфигурации. В дальнейшем если у нас появляется новый заказчик мы дорисовываем новый столбец в нашей таблице. При добавлении новой функции мы прописываем как она будет работать у всех заказчиков. Как тестировать систему у которой есть конфигурации а следовательно поведение определяется настройками а не жестко заданным алгоритмом. В такой ситуации вам придется в тестах определять к какой конфигурации они относятся. Ну и для конфигураций этих клиентов не писать тесты проверяющие функции ф2 и ф3. Теперь мы готовы к новым релизам и новым установкам у новых клиентов.
Как вы понимаете количество заказчиков растет, количество функций тоже и конечно растет количество тестов.
В начале каждый разработчик тестирует системы непосредственно на свое рабочей машине. Компилирует системы, разворачивает БД.
…А дальше запуск всех тестов начал занимать более 4,5 часов
Соответственно запуск тестов парализовал основную работу, т.к. при исправлении одной строчки кода требовалось много времени чтобы настроить среду, дождаться выполнения тестов. А иногда исправление нужно сделать и тут же приступить к следующей задаче.
В итоге, чтобы сэкономить время тесты начали запускать редко, увеличилось число тестов в красной зоне. Иногда становилось понятно что тесты не запускали по несколько недель. Мы поняли что так дело не пойдет, что нам нужно получать результат тестирования как можно быстрее, в течении 5-10 минут
Мы купили высокопроизводительный сервер, но и это сняло проблему только частично.
Что бы вы могли в такой ситуации порекомендовать?
Сначала я вам могу порекомендовать попробовать выделить в группы тесты с похожими исходными данными и выполнять эти группы тестов параллельно. Самые тяжелые тесты, например нагрузочные, выполнять по ночам.
И мы пришли к распределенным тестам. Получается что, мы можем как угодно быстро выполнить наши модульные и функциональные тесты, увеличивая число виртуальных машин. Но как управлять таким запуском тестов и получать отчеты об их выполнении.. Разработчикам достаточно проблематично заходить на каждую виртуальную машину и запускать тесты. Можно вообще забыть зайти на какую то машину и запустить на ней тесты. В итоге мы просто перестали контролировать ситуацию, тесты не запускались, т.к. это очень долго, все настроить, посетить разные сервера и т.д.
И так, мы имеем распределенные тесты, которые выполняются очень быстро, но нам нужно автоматизация. И мы вот что решили применить.
В такой ситуации вам нужен сервер непрерывной интеграции. Он применяется для того, чтобы применять изменения в системе как можно раньше. Каждое изменение должно сразу проверятся, т.е. запускаться тесты. Таким образом сервер убирает много ручной работы, тесты запускаются независимо от желания разработчика.
Как работает сервер непрерывной интеграции.
Этот сервер следить за изменениями в системе контроля версий и как тольно он обнаруживает изменения, срабатывает триггер которые запускает интеграцию. Получаются последние версии исходных файлов. Производится компиляция, накатка скриптов на тестовую БД, запускаются модульные и функциональные тесты на всех виртуальных машинах. В результате работы формируются отчеты. Которые приходят всем разработчикам
. Каждый сервер непрерывной интеграции следит за своей веткой разработки. В результате интеграции формируются отчеты которые присылаются всей группе разработки. Таким образом мы можем подходить гибко к тестированию каждой ветки. Где то такие тесты запускаются где то другие.
И так мы прошли с вами полный путь постановки процесса функционального тестирования. Чего мы достигли. Тесты выполняются быстро и отчеты приходят через 5 минут. Автоматическая сборка следит за тем, что бы не был сохранен в контроль версий некомпилируемый код. Получая результаты тестов мы можем продолжать разработку. Мы не ждем выполнения тяжелых тестов, отчеты об их выполнении читаем утром. На каждую ветку разработки свой сервер интеграции.