Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coverlet.collector not adding a .NET MAUI project to the coverage.cobertura.xml #1423

Closed
daveikaye2 opened this issue Dec 7, 2022 · 4 comments

Comments

@daveikaye2
Copy link

daveikaye2 commented Dec 7, 2022

I have a .NET MAUI project and a (Unit) Tests project in the same solution. The Tests project references the .NET MAUI project and the tests run fine. I want to also add code coverage for the .NET MAUI project. However, I am unable to get this to work with coverlet.collector as the produced coverage.cobertura.xml does not include the .NET MAUI project (as one of the packages).

Why is it not picking up the .NET MAUI project?

Below is my proj file for the Tests project:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <IsPackable>false</IsPackable>
        <EnableNETAnalyzers>true</EnableNETAnalyzers>
        <Nullable>enable</Nullable>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
        <PackageReference Include="xunit" Version="2.4.2" />
        <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
            <PrivateAssets>all</PrivateAssets>
        </PackageReference>
        <PackageReference Include="coverlet.collector" Version="3.2.0">
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
            <PrivateAssets>all</PrivateAssets>
        </PackageReference>
        <PackageReference Include="FluentAssertions" Version="6.8.0" />
        <PackageReference Include="NSubstitute" Version="4.4.0" />
    </ItemGroup>
    <ItemGroup>
      <ProjectReference Include="..\..\Source\MauiApp.Client\MauiApp.Client.csproj" />
      <ProjectReference Include="..\..\Source\Service\Service.csproj" />
    </ItemGroup>
    <ItemGroup>
      <Folder Include="Service\" />
    </ItemGroup>
</Project>

Below is my proj file for the .NET MAUI project:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <!--<TargetFrameworks>net6.0-ios;net6.0</TargetFrameworks>-->
        <TargetFrameworks>net6.0</TargetFrameworks>
        <TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">net6.0-windows10.0.19041.0;$(TargetFrameworks)</TargetFrameworks>
        <!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
        <!-- <TargetFrameworks>$(TargetFrameworks);net6.0-tizen</TargetFrameworks> -->
        <OutputType Condition="'$(TargetFramework)' != 'net6.0'">Exe</OutputType>
        <RootNamespace>$(MSBuildProjectName.Replace("-", "_"))</RootNamespace>
        <UseMaui>true</UseMaui>
        <SingleProject>true</SingleProject>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <!-- Display name -->
        <ApplicationTitle>GridSwift</ApplicationTitle>
        <!-- App Identifier -->
        <ApplicationId>someapp.gist</ApplicationId>
        <ApplicationIdGuid>CCB22D0C-6528-4C55-9BB7-2CAB312363AB</ApplicationIdGuid>
        <!-- Versions -->
        <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
        <ApplicationVersion>1</ApplicationVersion>
        <!-- <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.4</SupportedOSPlatformVersion>-->
        <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.19041.0</SupportedOSPlatformVersion>
        <TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.19041.0</TargetPlatformMinVersion>
        <DefaultLanguage>en-us</DefaultLanguage>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net6.0-windows10.0.19041.0|AnyCPU'">
      <TreatWarningsAsErrors>True</TreatWarningsAsErrors>
    </PropertyGroup>
    <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0-windows10.0.19041.0|AnyCPU'">
      <TreatWarningsAsErrors>True</TreatWarningsAsErrors>
    </PropertyGroup>
    <ItemGroup>
        <!-- App Icon -->
        <MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
        <!-- Splash Screen -->
        <MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
        <!-- Images -->
        <MauiImage Include="Resources\Images\*" />
        <MauiImage Update="Resources\Images\dotnet_bot.svg" BaseSize="168,208" />
        <!-- Custom Fonts -->
        <MauiFont Include="Resources\Fonts\*" />
        <!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
        <MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
    </ItemGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.Identity.Client" Version="4.48.0" />
        <PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
        <PackageReference Include="ReduxSimple" Version="3.7.0" />
    </ItemGroup>
    <ItemGroup>
      <MauiXaml Update="Views\LoginView.xaml">
        <Generator>MSBuild:Compile</Generator>
      </MauiXaml>
    </ItemGroup>
</Project>

I run the following command under the Tests project root: dotnet test --collect:"XPlat Code Coverage"
...and eventually get the following output:

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
Passed!  - Failed:     0, Passed:    22, Skipped:     0, Total:    22, Duration: 199 ms - Tests.dll (net6.0)
Attachments:
  C:\Users\T702180\code\MyApp\Testing\Tests\TestResults\4a6ce0bf-8748-4f58-9fe9-b3ae8a0958a0\coverage.cobertura.xml

All the tests pass, including the ones covering the MauiApp.Client.

Below are the contents of the coverage.cobertura.xml file:

<?xml version="1.0" encoding="utf-8"?>
<coverage line-rate="0.37929999999999997" branch-rate="0.3285" version="1.9" timestamp="1670364272" lines-covered="239" lines-valid="630" branches-covered="23" branches-valid="70">
  <sources>
    <source>C:\Users\T702180\code\MyApp\Source\Service\</source>
  </sources>
  <packages>
    <package name="Service" line-rate="0.37929999999999997" branch-rate="0.3285" complexity="211">
      ...
    </package>
  </packages>
</coverage>

As you can see, the coverage.cobertura.xml file is missing the MauiApp.Client project (package). However, it picks-up the Service project, which is just a plain .NET 6 project (non-MAUI).

I am seeing the same behavior locally on my Windows 10 machine as well as in the ADO pipeline.

@ASankey-Ideagen
Copy link

This is being caused by xaml files being included within the project. For some reason it is blocking coverage from completing. Removing those files allows coverage to complete as expected.

A work around is to either convert any xaml into code or move all xaml files into their own project and reference them from there.

@daveMueller
Copy link
Collaborator

The reason is that MAUI internally uses some source generators.

[coverlet] Unable to instrument module: D:\Repos\Repros\MauiApp1423\MauiApp1423Tests\bin\Debug\net6.0\MauiApp1423.dll, pdb without local source files, [D:\Repos\Repros\MauiApp1423\MauiApp1423\Microsoft.Maui.Controls.SourceGen\Microsoft.Maui.Controls.SourceGen.CodeBehindGenerator\App.xaml.sg.cs]

The current released versions of coverlet are a bit sensitive to code in the pdb that can't be matched to actual source files. If an assembly contains code that can't be mapped to a source file the assembly won't be instrumented and thus isn't included in the final report.

There is a upcoming breaking change of this mapping algorithem in coverlet that is more open to that. You can read about this here and here. With those changes the MAUI project won't be excluded from instrumentation anymore and will appear in the reports by default.

grafik

The drawback now is that the source generator files are also listed in the report. To clean up the generated report you can just add an exclusion filter <ExcludeByFile>**/*.sg.cs</ExcludeByFile> to coverlet.

grafik

As this change in coverlet isn't released yet you can consume the nightly build that already contains it. You can read about consuming the nightly here. (I also created the reports from the screenshots with the nightly version.)

@daveMueller
Copy link
Collaborator

I'm closing this as it seems to be resolved in the upcoming version. Feel free to reopen.

@ChristopherStephan
Copy link

We found out that we need to add coverlet.msbuild as a package reference to the MAUI test project to have the coverage report being generated. Previously with the Xamarin.Forms app, coverlet.collector was sufficient.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants