feat: replace MSTest/xunit/coverlet with TUnit, dotnet-coverage, and CI coverage reporting - #134
Conversation
…and new tests - Replace MSTest + xunit + coverlet with TUnit 1.64.13 (Microsoft Testing Platform native) - Convert all 30+ test files from MSTest/xunit to TUnit ([Test], [Arguments], [Before(Test)], await Assert.That) - Add dotnet tool manifest for dotnet-coverage and reportgenerator - Update CI workflow: dotnet-coverage collect, ReportGenerator HTML+MarkdownSummaryGithub, workflow step summary, sticky PR coverage comment - Add new test coverage: SpecificationTests, TaskExtensionsTests, ErrorResultTests, ArrayExtensionsTests Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR migrates the SharedCode solution’s testing and coverage tooling from the legacy MSTest/xUnit/coverlet stack to TUnit (Microsoft Testing Platform), and updates CI to collect and publish coverage summaries and PR comments.
Changes:
- Converted the existing unit tests to TUnit attributes/assertions and introduced a few new test files for additional coverage.
- Updated test projects to run as executables (MTP/TUnit) and centralized TUnit package versioning.
- Reworked CI to run the test executables under
dotnet-coverageand publish ReportGenerator HTML + Markdown summaries (step summary + sticky PR comment).
Reviewed changes
Copilot reviewed 44 out of 44 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| SharedCode.Data.Tests/QueryResultTests.cs | Migrates QueryResult tests from MSTest to TUnit assertions. |
| SharedCode.Data.Tests/PagingDescriptorTests.cs | Migrates PagingDescriptor tests from MSTest to TUnit assertions. |
| SharedCode.Data.Tests/PageBoundryTests.cs | Migrates PageBoundry tests from MSTest to TUnit assertions. |
| SharedCode.Data.Tests/Data.Tests.csproj | Switches test project to TUnit/MTP executable model and updates references. |
| SharedCode.Core.Tests/ValueObjectTests.cs | Migrates ValueObject tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/TypeExtensionsTests.cs | Migrates TypeExtensions tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/Threading/TaskExtensionsTests.cs | Adds new TUnit tests for TaskExtensions.SafeFireAndForgetAsync. |
| SharedCode.Core.Tests/Text/StringExtensionsTests.cs | Migrates StringExtensions tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/Text/StringBuilderExtensionsTests.cs | Migrates StringBuilderExtensions tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/Specifications/SpecificationTests.cs | Adds new TUnit tests for specification evaluation/configuration behavior. |
| SharedCode.Core.Tests/Security/HasherTests.cs | Migrates Hasher tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/PropertySupportTests.cs | Migrates PropertySupport tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/NumberExtensionsTests.cs | Migrates NumberExtensions tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/Models/EntityTests.cs | Migrates Entity tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/Linq/PredicatesTests.cs | Migrates from xUnit/AwesomeAssertions to TUnit assertions. |
| SharedCode.Core.Tests/Linq/EnumerableExtensionsTests.cs | Migrates EnumerableExtensions tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/Linq/CollectionExtensionsTests.cs | Migrates CollectionExtensions tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/LambdaComparer.cs | Removes MSTest suppression attribute; keeps comparer helper. |
| SharedCode.Core.Tests/IntExtensionsTests.cs | Migrates IntExtensions tests from MSTest to TUnit assertions/arguments. |
| SharedCode.Core.Tests/FunctionExtensionsTests.cs | Migrates FunctionExtensions tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/FluentTimeSpanTests.cs | Migrates FluentTimeSpan tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/ExtensionsTests.cs | Migrates Extensions tests from MSTest to TUnit assertions/arguments. |
| SharedCode.Core.Tests/ExceptionExtensionsTests.cs | Migrates ExceptionExtensions tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/EventHandlerExtensionsTests.cs | Migrates EventHandlerExtensions tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/EnumTTests.cs | Migrates Enum tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/EnumExtensionsTests.cs | Migrates EnumExtensions tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/Domain/ResultTests.cs | Migrates Result domain tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/Domain/ErrorResultTests.cs | Adds additional TUnit coverage for ErrorResult variants. |
| SharedCode.Core.Tests/Core.Tests.csproj | Switches Core test project to TUnit/MTP executable model and updates references. |
| SharedCode.Core.Tests/CompareFunc.cs | Removes MSTest suppression attribute; keeps delegate helper. |
| SharedCode.Core.Tests/Collections/EnumerationUtilitiesTests.cs | Migrates EnumerationUtilities tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/Collections/ArrayExtensionsTests.cs | Adds new TUnit tests for ArrayExtensions conversion/list helpers. |
| SharedCode.Core.Tests/Calendar/DayOfWeekExtensionsTests.cs | Migrates calendar tests from MSTest to TUnit assertions/arguments. |
| SharedCode.Core.Tests/Calendar/DateTimeOffsetCalendarExtensionsTests.cs | Migrates calendar tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/Calendar/DateTimeExtensionsTests.cs | Migrates calendar tests and updates culture handling for TUnit execution. |
| SharedCode.Core.Tests/BaseExceptionTests.cs | Migrates BaseException tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/Attributes/AttributeTests.cs | Migrates attribute tests from MSTest to TUnit assertions. |
| SharedCode.Core.Tests/AssertExtensions.cs | Replaces MSTest-based helper assertions with TUnit-based helpers. |
| SharedCode.Core.Tests/AssemblyExtensionsTests.cs | Migrates AssemblyExtensions tests from MSTest to TUnit assertions. |
| Directory.Packages.props | Removes legacy test packages and adds TUnit version; updates select framework package versions. |
| .github/workflows/dotnet.yml | Updates CI to build, run TUnit executables under dotnet-coverage, and publish coverage summaries/comments. |
| .github/scripts/run-tunit-tests.sh | Adds bash runner for TUnit test executables. |
| .github/scripts/run-tunit-tests.ps1 | Adds PowerShell runner for TUnit test executables (used by CI). |
| .config/dotnet-tools.json | Adds local tools for dotnet-coverage and reportgenerator. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…-throw tests, add code-review skill Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 45 out of 45 changed files in this pull request and generated no new comments.
Suppressed comments (6)
.github/workflows/dotnet.yml:47
- Same as above:
reportgeneratoris restored as a local tool from.config/dotnet-tools.json, so invoking it viadotnet tool run reportgeneratoravoids relying on PATH/shims.
- name: Generate coverage report
if: always()
run: >
reportgenerator
-reports:coverage.xml
SharedCode.Core.Tests/Core.Tests.csproj:13
WarningsNotAsErrorsfor AD0001 has the same effect of hiding analyzer crashes. If there’s no documented/temporary analyzer failure being worked around, it’s better to remove this so CI fails loudly when analyzers crash.
<TargetFrameworks>net9.0;net10.0</TargetFrameworks>
<WarningsNotAsErrors>$(WarningsNotAsErrors);AD0001</WarningsNotAsErrors>
.github/workflows/dotnet.yml:6
- Workflow-wide
pull-requests: writepermission is broader than necessary; only the job that posts the sticky PR comment needs it. Consider keeping the workflow default ascontents: readand movingpull-requests: writeunder thetestjob permissions to follow least-privilege.
permissions:
contents: read
pull-requests: write
.github/workflows/dotnet.yml:42
dotnet tool restorerestores local tools from.config/dotnet-tools.json, but the reliable way to invoke them in CI isdotnet tool run <command>rather than callingdotnet-coveragedirectly (which depends on PATH/shims).
This issue also appears on line 43 of the same file.
- name: Run tests with coverage
shell: pwsh
run: >
dotnet-coverage collect
--output coverage.xml
SharedCode.Core.Tests/Core.Tests.csproj:9
- Suppressing AD0001 (
AnalyzerFailure) viaNoWarncan mask analyzer crashes that should be investigated (especially since analyzers are treated as errors). If this suppression isn’t strictly required for a known issue, remove it so analyzer failures surface normally.
This issue also appears on line 12 of the same file.
<NoWarn>$(NoWarn);AD0001</NoWarn>
<OutputType>Exe</OutputType>
SharedCode.Data.Tests/Data.Tests.csproj:13
- Suppressing AD0001 (
AnalyzerFailure) viaNoWarn/WarningsNotAsErrorscan mask analyzer crashes that should be investigated. If this isn’t required for a known, tracked issue, remove these properties so analyzer failures surface normally.
…enerator Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 45 out of 45 changed files in this pull request and generated 2 comments.
Suppressed comments (1)
SharedCode.Core.Tests/Core.Tests.csproj:28
AwesomeAssertions,AwesomeAssertions.Analyzers, andAwesomeAssertions.Jsonare still referenced here, but there are no remainingAwesomeAssertionsusages inSharedCode.Core.Testsafter the TUnit migration. Removing these unused PackageReferences will reduce restore time and dependency surface.
<ItemGroup>
<PackageReference Include="AwesomeAssertions" />
<PackageReference Include="AwesomeAssertions.Analyzers">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
… runner Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 45 out of 45 changed files in this pull request and generated no new comments.
Suppressed comments (4)
SharedCode.Data.Tests/Data.Tests.csproj:13
AD0001is being both suppressed (NoWarn) and downgraded (WarningsNotAsErrors), which is redundant and completely hides analyzer crashes. Consider keeping it visible but non-fatal by removingNoWarnand documenting whyAD0001is being downgraded.
SharedCode.Core.Tests/Threading/TaskExtensionsTests.cs:26- This test uses a fixed delay (
Task.Delay(50)) to assert a callback wasn’t invoked.SafeFireAndForgetAsyncawaitsTask.CompletedTasksynchronously and cannot invoke the exception callback, so the delay only slows the suite and introduces a time-based dependency.
SharedCode.Core.Tests/Core.Tests.csproj:13 AD0001is being both suppressed (NoWarn) and downgraded (WarningsNotAsErrors), which is redundant and completely hides analyzer crashes. Consider keeping it visible but non-fatal by removingNoWarnand documenting whyAD0001is being downgraded.
<NoWarn>$(NoWarn);AD0001</NoWarn>
.github/workflows/dotnet.yml:57
- Posting a sticky PR comment will fail on forked pull requests because
GITHUB_TOKENis read-only in that context. Guard this step so CI doesn’t fail on forks.
- name: Post coverage comment on PR
if: always() && github.event_name == 'pull_request'
uses: marocchino/sticky-pull-request-comment@v2
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 45 out of 45 changed files in this pull request and generated no new comments.
Suppressed comments (5)
SharedCode.Data.Tests/QueryResultTests.cs:19
- This file still uses tab indentation (e.g., on the test attributes/methods). The repo conventions specify 4-space indentation with no tabs; please convert the indentation in this file to spaces to keep formatting consistent and avoid churn in future diffs.
SharedCode.Data.Tests/PagingDescriptorTests.cs:18 - This file uses tab indentation for the new TUnit tests. SharedCode formatting guidelines require 4-space indentation and no tabs; please convert tabs to spaces throughout the file.
.github/workflows/dotnet.yml:41 - The PR description says CI runs
dotnet-coverage collect -- dotnet test, but the workflow now runs a custom PowerShell runner script that executes the built test assemblies directly. Please either update the PR description to match, or switch the workflow to usedotnet testif that’s still the intended approach (to preserve standard test execution semantics like filtering/logging).
- name: Run tests with coverage
shell: pwsh
run: >
dotnet tool run dotnet-coverage collect
--output coverage.xml
--output-format cobertura
--
pwsh -NoLogo -NoProfile -File ./.github/scripts/run-tunit-tests.ps1
SharedCode.Data.Tests/PageBoundryTests.cs:16
- This test file is indented with tabs. To match the solution formatting rules (4 spaces, no tabs), please convert indentation to spaces.
SharedCode.Core.Tests/Core.Tests.csproj:28 - After the migration,
AwesomeAssertionsandNewtonsoft.Jsonappear to be unused inSharedCode.Core.Tests(no code references remain). Keeping them increases restore/build time and dependency surface; consider removing these package references if they’re no longer needed.
<ItemGroup>
<PackageReference Include="AwesomeAssertions" />
<PackageReference Include="AwesomeAssertions.Analyzers">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="AwesomeAssertions.Json" />
<PackageReference Include="GCop.All.Common">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="TUnit" />
SummarySummary
CoverageSharedCode.Core - 27.3%
SharedCode.Core.Tests - 98.1%
SharedCode.Data - 8.3%
SharedCode.Data.Tests - 100%
|
Replaces the legacy test stack (MSTest + xunit + coverlet) with TUnit 1.64.13 on the Microsoft Testing Platform (MTP), adds
dotnet-coveragefor collection, and wiresreportgeneratorinto CI to produce workflow step summaries and sticky PR coverage comments.Package changes
MSTest.TestAdapter,MSTest.TestFramework,Microsoft.NET.Test.Sdk,xunit,xunit.runner.visualstudio,coverlet.collector,GitHubActionsTestLoggerTUnit1.64.13 to both test projects.config/dotnet-tools.json:dotnet-coverage,dotnet-reportgenerator-globaltoolTest conversion (~30 files)
All tests migrated to TUnit idioms:
[TestInitialize]/[TestCleanup]→[Before(Test)]/[After(Test)];[Ignore]→[Skip("reason")]; xunit[Fact]and AwesomeAssertions.Should()calls also converted.New test coverage
Added
SpecificationTests,TaskExtensionsTests,ErrorResultTests, andArrayExtensionsTestsfor previously uncovered areas.CI workflow
dotnet tool restore+dotnet-coverage collect -- dotnet testreportgeneratoroutputs HTML +MarkdownSummaryGithub$GITHUB_STEP_SUMMARYmarocchino/sticky-pull-request-comment@v2pull-requests: writepermission to the job