Сегодня я читал сообщение Скотта Хансельмана о покрытии кода в проектах .Net Core. Внезапно я начал копаться в сообщениях об инструментах, о которых я никогда не слышал, но это звучало довольно интересно, таких как Coverlet и ReportGenerator. Тогда я подумал, что они могут вписаться в наши потоки CI.
Признаюсь, когда я начинал разработку .NET, я вообще не занимался модульным тестированием. Однако, благодаря таким хорошим людям, как Луис Фрайле и Унаи Зоррилла Кастро, я вскоре понял, что они настолько важны, что я не смогу жить без них. Итак, я принял Microsoft's MsTest и начал писать множество [TestClass] и [TestMethod]. Потом в какой-то момент я услышал о xUnit, и снова все изменилось. Я забыл об атрибутах [TestClass] и начал писать [Fact] s и [Theory] es.
Я использую их в течение долгого времени, но проблема, которую я обнаружил при переходе с MsTest на xUnit, заключалась в том, что информация, отображаемая в результатах сборки Visual Studio Team Services, была очень плохой, чтобы быть вежливой. И данных о покрытии кода вообще не было. Это действительно было плохо, но я ленив и отложил задачу по улучшению этого до сегодняшнего дня.
Покрывало
Первое, что я сделал, - это частично реализовал изменения, предложенные Скоттом Хансельманом, чтобы включить покрытие кода в мой проект. Coverlet - это пакет, который можно включить в ваши проекты и генерировать информацию о покрытии кода во время сборки. В проекте говорится, что это буквально «кроссплатформенная библиотека покрытия кода для .NET Core с поддержкой покрытия строк, ветвей и методов».
Чтобы включить цели сборки Coverlet в свой проект, вы должны добавить следующую строку в файл csproj вашего тестового проекта:
<PackageReference Include="coverlet.msbuild" Version="2.0.1" />
Вы можете узнать, как это происходит, прочитав его домашнюю страницу Github, но в основном вы можете сгенерировать файл покрытия кода в нескольких распространенных форматах, вызвав тест dotnet с параметром CollectCoverage.
dotnet test /p:CollectCoverage=true
По умолчанию это создает файл покрытия кода в формате JSON. Если вы хотите поэкспериментировать с расширением Visual Studio Code Coverage Gutters, как это было предложено Хансельманом, вы можете использовать такую задачу в своем файле .vscode / tasks.json:
{ "label": "test with coverage", "command": "dotnet", "type": "process", "args": [ "test", "/p:CollectCoverage=true", "/p:CoverletOutputFormat=lcov", "/p:CoverletOutput=./lcov", "${workspaceFolder}/test/WebUserManager.Test/WebUserManagerTests.csproj" ], "problemMatcher": "$msCompile", "group": { "kind": "test", "isDefault": true } }
Файл lcov.info можно проанализировать с помощью расширения Coverage Gutters и показать, какие строки охватываются вашими тестами. Это может быть очень удобно при локальной разработке, но для CI в VSTS нам потребуется использовать другой формат файла, понятный нашему инструменту создания отчетов. Это формат, используемый Cobertura, утилитой покрытия кода для Java, и его можно сгенерировать, вызвав dotnet test со следующими параметрами:
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura
Будет создан файл с именем extension.cobertura.xml. Только это можно использовать для публикации данных о покрытии кода в результатах сборки VSTS. Однако мы сделаем еще один шаг и создадим полный отчет, который можно будет просматривать и просматривать со ссылкой на исходный код.
ReportGenerator
Инструмент, который нам понадобится, называется ReportGenerator, и его основное применение - создание красивых отчетов в нескольких форматах из файлов покрытия кода в других форматах. В нашем случае мы собираемся сгенерировать HTML-файл из нашего файла extension.cobertura.xml.
ReportGenerator - это исполняемый файл, который можно легко загрузить и запустить. Но поскольку мы не хотим зависеть от инструментов, установленных в наших агентах, мы загрузим сборку и установим инструмент по запросу. Для этого мы добавим его в наш проект как инструмент командной строки dotnet. Просто добавьте следующие строки в файл .csproj вашего тестового проекта:
<ItemGroup> <DotNetCliToolReference Include="dotnet-reportgenerator-cli" Version="4.0.0-alpha12" /> </ItemGroup>
ПРИМЕЧАНИЕ: это альфа-версия инструмента, поэтому будьте готовы столкнуться с потенциальными проблемами и изменениями без уведомления. Если вам нужно что-то более стабильное, вы можете загрузить и установить ReportGenerator.exe в папку ваших агентов сборки и соответствующим образом установить PATH.
Теперь ваш файл тестера .csproj должен выглядеть примерно так:
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp2.1</TargetFramework> <IsPackable>False</IsPackable> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\..\src\App\Acme.App.csproj" /> <ProjectReference Include="..\..\src\Domain\Acme.Domain.csproj" /> <ProjectReference Include="..\..\src\Infrastructure\Acme.Infrastructure.csproj" /> </ItemGroup> <ItemGroup> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" /> <PackageReference Include="xunit" Version="2.3.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" /> <PackageReference Include="Moq" Version="4.8.2" /> <PackageReference Include="coverlet.msbuild" Version="2.0.1" /> </ItemGroup> <ItemGroup> <DotNetCliToolReference Include="dotnet-reportgenerator-cli" Version="4.0.0-alpha12" /> </ItemGroup> <ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1' "> <PackageReference Include="Microsoft.CodeCoverage" Version="1.0.3" /> </ItemGroup> </Project>
Настроить определение сборки
Теперь, когда мы правильно настроили проект, пришло время настроить определение сборки. Помните, что следующие шаги не сработают, если вы не изменили свой проект с помощью пакетов NuGet, определенных ранее.
Ниже вы можете увидеть пример определения сборки. Нас интересуют три выделенные задачи.
Первая задача запускает тесты с помощью средства запуска тестов xUnit и генерирует файл покрытия кода. Вторая задача берет сгенерированный файл и строит подробный отчет, связанный с исходным кодом. Третья задача публикует два предыдущих результата, чтобы их можно было отобразить на панели результатов сборки. Давайте посмотрим на каждого подробно.
Тестирование и сбор покрытия
Это задача .NET Core со следующими параметрами:
- Команда: test
- Путь к проекту (ам): выберите только один тестовый проект. Должно быть возможно выбрать более одного с шариками, но я не пробовал.
- Аргументы:
/p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=$(Build.SourcesDirectory)\TestResults\Coverage\
Обратите внимание, как мы устанавливаем формат вывода на cobertura и папку, в которой вывод будет оставлен в подпапке с именем TestResults \ Coverage.
Генератор отчетов
Вторая задача также является задачей .NET Core со следующими параметрами:
- Команда: custom
- Путь к проекту (ам): такой же, как у первой задачи
- Пользовательская команда: генератор отчетов
- Рабочий каталог: установите в папку тестового проекта.
- Аргументы:
"-reports:$(Build.SourcesDirectory)\TestResults\Coverage\coverage.cobertura.xml" "-targetdir:$(Build.SourcesDirectory)\TestResults\Coverage\Reports" -tag:$(Build.BuildNumber) -reportTypes:htmlInline
Здесь мы вызываем инструмент командной строки .Net Core ReportGenerator.exe, как объяснялось ранее, устанавливая для входного файла значение extension.cobertura.xml, формат вывода - Встроенный HTML (без внешних файлов js и изображений) и выходная папка в TestResults \ Coverage \ Reports.
ПРИМЕЧАНИЕ: обратите внимание на кавычки вокруг некоторых параметров, особенно тех, которые содержат пути.
На данный момент мы создали файл покрытия и отчет в следующих местах:
- $ (Build.SourcesDirectory) \ TestResults \ Coverage \ охват.cobertura.xml
- $ (Build.SourcesDirectory) \ TestResults \ Coverage \ Report \ *. htm
Опубликовать данные о покрытии
Последняя задача просто публикует сгенерированные данные. Добавьте задачу «Опубликовать результаты покрытия кода» со следующими значениями:
- Инструмент покрытия кода: Cobertura
- Сводный файл: $ (Build.SourcesDirectory) \ TestResults \ Coverage \ ** \ охват.cobertura.xml
- Каталог отчета: $ (Build.SourcesDirectory) \ TestResults \ Coverage \ Reports
Вот и все. Окончательные результаты будут такими:
Больше информации:
- Https://www.hanselman.com/blog/AutomaticUnitTestingInNETCorePlusCodeCoverageInVisualStudioCode.aspx
- Https://github.com/tonerdo/coverlet
- Https://danielpalme.github.io/ReportGenerator/
- Https://github.com/danielpalme/ReportGenerator/wiki/Integration
- Https://www.nuget.org/packages/dotnet-reportgenerator-cli/
- Https://dotnetoughtts.net/code-coverage-in-netcore-with-coverlet/
- Https://docs.microsoft.com/en-us/dotnet/core/tools/extensibility#per-project-based-extensibility
- Https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters