Встраиваем сбор Code Coverage в CruiseControl.NET

    Введение


    Последнее время активно пропагандируется практика разработки программного обеспечения Test-Driven Development. Бесспорно, она очень полезна, но не всегда и не все ее применяют. Поэтому часть кода покрыта юнит-тестами, а часть остается непокрытой. Проследить за каждым проектом вручную, нормально написаны там тесты или нет, является практически невыполнимой задачей.
    Недавно я задался вопросом, а как можно автоматизировать процесс сбора метрики, которая показывает процент покрытия кода тестами. Было решено встроить ее сбор в CruiseControl.NET. Естественно, что 100% покрытие не гарантирует отсутствие багов, но хотя бы показывает отношение разработчиков к написанию тестов.

    image


    В данной статье я не буду останавливаться на моментах касающихся настройки CruiseControl’а для сборки проектов и запуска юнит-тестов. Будут описаны шаги, которые позволят собрать необходимую информацию о покрытии кода и вывести ее на странице с тестами. Для написания юнит-тестов наша компания использует фреймворк от Microsoft – MSTest. Результаты работы с этим фреймворком и будут описываться в статье. Стоит заметить, что необходимым условием для встраивания покрытия кода является изначальная настройка CruiseControl'а для запуска тестов.

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

    Всё нижеописанное относится к проектам, написанным в Visual Studio 2010. Отличия с 2008 версией хоть и небольшие, но они есть.

    Создание data.coverage файла на билд-сервере


    Visual Studio позволяет настроить выполнение тестов таким образом, чтобы после прохождения всех тестов создавался файл, в котором будет храниться информация о покрытых участках кода. Называться этот файл будет data.coverage (хранится он в папке In с результатами прохождения тестов).
    Эта настройка хранится в файле .testrunconfig вашего проекта. Через UI ее можно выставить следующим образом:
    1. Откройте ваш файл .testrunconfig
    2. Выберите пункт Data and Diagnostics
    3. Выставите флажок напротив Code Coverage и нажмите Configure
    4. Выберите библиотеку, для которой необходимо собирать покрытие
    5. Выключите флажок Instrument assemblies in place

    После сохранения файла внутри него будет следующий текст:

    <?xml version="1.0" encoding="UTF-8"?>
    <TestSettings name="Local Test Run" id="de0d45b4-4fed-4acb-a663-2cfdf0ce4fd7" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
     <Description>This is a default test run configuration for a local test run.</Description>
     <Deployment enabled="false" />
     <Execution>
      <Timeouts testTimeout="300000" />
      <TestTypeSpecific>
       <UnitTestRunConfig testTypeId="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b">
        <AssemblyResolution>
         <TestDirectory useLoadContext="true" />
        </AssemblyResolution>
       </UnitTestRunConfig>
      </TestTypeSpecific>
      <AgentRule name="LocalMachineDefaultRole">
       <DataCollectors>
        <DataCollector uri="datacollector://Microsoft/CodeCoverage/1.0" assemblyQualifiedName="Microsoft.VisualStudio.TestTools.CodeCoverage.CoveragePlugIn, Microsoft.VisualStudio.QualityTools.Plugins.CodeCoverage, PublicKeyToken=b03f5f7f11d50a3a" friendlyName="Code Coverage">
         <Configuration>
          <CodeCoverage xmlns="">
           <Regular>
            <CodeCoverageItem binaryFile="YourProject\bin\Debug\YourProject.dll" pdbFile="YourProject\bin\Debug\YourProject.pdb" />
           </Regular>
          </CodeCoverage>
         </Configuration>
        </DataCollector>
       </DataCollectors>
      </AgentRule>
     </Execution>
    </TestSettings>
    

    Секция DataCollectors как раз и говорит MSTest'у, что необходимо собирать Code Coverage.

    Теперь мы знаем, что должно быть указано в конфиге, и у нас есть 3 варианта его применения на билд-сервере:
    • использовать готовый файл конфига из вашего проекта;
    • хранить в проекте отдельный конфиг для билд-сервера;
    • создавать файл конфига на лету.

    Первый кейс нам не подходит, т.к. этот файл хранится в системе контроля версий, поэтому любой разработчик может выключить настройку по сбору Code Coverage и положить этот файл назад. Или наоборот, если мы, например, не хотим в некоторых случаях собирать эту метрику. По этим причинам настройка о том, собирать или не собирать метрику должна быть включена в CruiseControl. Второй вариант также не позволяет полностью предотвратить проблему описанную выше. По вышеописанным причинам мы у себя в компании остановились на третьем варианте. Описывать способ создания XML файла я не буду, там всё достаточно просто.

    Когда конфиг готов можно запускать тесты, для этого в конфиг файл CruiseControl'а в секцию с тасками необходимо добавить следующий код:

    <exec>
      <executable>C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\MSTest.exe</executable>
      <buildArgs>"/testcontainer:PathToWorkingDirectory\Source\bin\Release\YourTestProject.dll" "/runconfig:PathToYourConfig\localtestrun.testrunconfig" "/resultsfile:PathToWorkingDirectory\TestResults.xml"</buildArgs>
      <description>Executing MSTest</description>
    </exec>
    


    Если запустить сейчас CruiseControl, то файл data.coverage будет создан в папке PathToWorkingDirectory\[USERNAME]_[MACHINE-NAME] [DATE AND TIME]\In\[MACHINE-NAME]. Т.к. в названии папки присутствует время, то в дальнейшем будет не очень удобно использовать ее. Поэтому в .testrunconfig необходимо добавить следующую секцию (внутрь <TestSettings>):

    <NamingScheme baseName="FolderName" appendTimeStamp="false" useDefault="false" />
    


    Теперь файл data.coverage можно будет найти в папке PathToWorkingDirectory\FolderName\In\[MACHINE-NAME].

    После проделанных действий в папке с результатами тестов для этого проекта на машине с CruiseControl’ом будет находиться файл data.coverage. Проблема в том, что этот файл бинарный, поэтому нам необходимо сконвертировать его в xml.

    Конвертация data.coverage в XML


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

    using (CoverageInfo info = CoverageInfo.CreateFromFile(PathToDataCoverageFile))
    {
         CoverageDS data = info.BuildDataSet();
    
         string outputXml = data.GetXml();
         File.WriteAllText(PathToOutputXmlCoverageFile,outputXml));
    }
    


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

    Запуск нашего консольного приложения осуществляется благодаря дополнительной секции в конфиге билд-сервера:

    <exec>
      <executable>PathToConverter\Coverage2XmlConverter.exe</executable >
      <buildArgs>"PathToDataCoverage\data.coverage" "PathToOutputXml\coverage.xml"</buildArgs>
      <description>Calculation code coverage data</description>
    </exec>
    


    Добавление данных к результатам билда


    Теперь у нас почти всё готово. Достаточно добавить получившийся XML файл к результатам билда. Делается это достаточно просто, необходимо добавить следующую секцию в конфиг CruiseControl'а внутрь секции Publishers:

    <merge>
       <files>
         <file>PathToResults\TestResult.xml</file>
         <file>PathToCoverage\coverage.xml</file>
       </files>
    </merge>
    


    Файл TestResult.xml уже должен был быть у вас в конфиге, если у вас настроена работа с тестами.

    Отображение данных на странице с билдом


    Осталось написать файл XSLT для отображения собранных данных на страницу с билдом. На билдах, в которых покрытие составляет меньше 20%, показатель Code Coverage будет красным, в случае 20%-50% показатель будет желтым и в случае >50% он будет зеленым. Эти значения легко можно поменять в XSLT, и использовать те, которые больше вас устраивают.

    Общее значение покрытия мы показываем на странице с билдом, вот как теперь это выглядит:

    image

    Для этого пришлось немного модифицировать MSTestReport2008.xsl из стандартного набора CruiseControl.NET.

    А так выглядят детализация Code Coverage метрики:

    image

    Занимать место в статье текстом XSLT я не буду, поэтому выложил на GitHub 2 XSLT-файла, вместе с приложением для конвертации data.coverage файла в XML.

    Спасибо большое, буду раз замечаниям и дополнениям.

    Похожие публикации

    Средняя зарплата в IT

    110 500 ₽/мес.
    Средняя зарплата по всем IT-специализациям на основании 7 138 анкет, за 2-ое пол. 2020 года Узнать свою зарплату
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 21

      +1
      Спасибо, полезно.
        +1
        Не поленился разметить красиво все, но вот вопрос почему именно CruiseControl.NET?
          +1
          Так исторически сложилось. CC.NET позволяет легко его конфигурить, настраивать в какой последовательности всё билдить. Да и для того, чтобы переносить 200 с лишним проектов на другую билд-платформу, необходимо иметь достаточно веские основания.
            0
            200 проектов это да… Мы перенесли 10 своих на TeamCity и пока не нарадуемся.
              +2
              Я бы порекомендовал рассмотреть TeamCity как вариант. Перенос 200 проектов не должен будет занять ощутимое кол-во времени, но GUI nтам на порядок краше, единственный минус это отсутствие нормального разграничения прав в бесплатном варианте.
                0
                TeamCity — отличный вариант, но нужно представлять себе бонусы, которые будут получены (потеряны?) при миграции.
                При 200 проектах можно и вспомнить:
                — Светит солнышко?
                — Светит.
                — Ну вот и не трогай.
                  0
                  TeamCity дает 100 очков вперед обычному CruiseControl думаю с .NET тоже самое.
                  +1
                  Ну GUI, на мой взгляд не главное, задача же билд-сервера билдить :) Ну а что касается TeamCity, просто для переноса необходимо с ним самим разобраться, понять как его можно кастомизировать, вот на это и уйдет время. И не совсем сейчас видны существенные бенефиты, если всё и так просто великолепно работает.
                    0
                    Стукнитесь в skype — поделюсь впечатлениями.
              0
              Раз уж вы активно пользуетесь MSTests, то было бы полезно узнать:
              1. А есть ли поддержка запуска MSTests в 2008 Pro средствами самой студии?
              2. Можно ли запускать такие тесты на сервере без VS? Ведь это отдельная лицензия.
              3. Версий ncover 1.5.8.0 (x86) работает до сих пор и бесплатна, нет?
              4. Возможно ли использовать MSTests с Rhino.Mocks?
                0
                1. Да, Professional версия имеет встроенную поддержку тестирования через MSTest. Ей как раз и пользуемся
                2. На этот вопрос я не смогу ответить, т.к. в вопросы лицензирования я не вдавался, за это отвечает IT-отдел. :)
                3. Вот этого не знал, спасибо. Хотя непосредственно на сайте я этого не смог найти, только на форумах. Но это же версия 2008 года, насколько я понимаю?
                4. Я использую Moq, поэтому тут тоже точно не смогу ничего сказать, но думаю, что проблем не должно возникнуть.
                  0
                  1. Изначально это было невозможно, сообщество «продавило» видать.
                  2. NCover дешевле VS ;)
                  3. У меня сборка 2007 года. Сейчас она называется community edition на сайте, может пересобрали с новой лицензией?
                  +1

                  4. Возможно ли использовать MSTests с Rhino.Mocks?
                    +1
                    Да, можно. А почему вы усомнились? Rhino.Mocks это же обычная либа.

                    П.С. фак, как оно умудряется отправлять само…
                  +2
                  Не устаю радоваться CC.NET — бесплатный, легкий и невероятно гибкий билд-сервер.
                  Можно дописывать любые надстройки, выстраивать любые стратегии сборки и кастомизировать все, что угодно!
                  Этакий конструктор — «собери сам», в отличии от готовых платных решений. В последних не всегда удается сделать то, что нужно, а начнешь кастомизировать — упираешься в массу ограничений.
                    +2
                    Мм, чем вас не устроил TeamCity, например?
                    К слову, там покрытие из коробки
                      0
                      Узнал про TeamCity. Огромное спасибо!
                        0
                        Может, вы и про Resharper / Youtrack не знаете?:))
                          0
                          Нет, с этим продуктами Jet Brains, ровно как и с IDEA, знаком хорошо.
                    0
                    В 5ой версии были достаточно жёсткие ограничения на free версию.
                      0
                      Используем на проекте TeamCity + встроенный в него dotCover. Настраивается это все минут за 15 через GUI. Советую попробовать для какого-нибуть нового проекта — очень классное решение, у меня одни позитивные эмоции.

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

                      Самое читаемое