Skip to content

Commit

Permalink
refactor: disable explicit .NET7 and upgrade to xunit v3 (#728)
Browse files Browse the repository at this point in the history
Upgrade testing projects to [xunit v3](https://xunit.net/docs/getting-started/v3/migration) and remove the .NET Stryker mutation badge, because [Stryker.NET doesn't handle xUnit v3 properly](stryker-mutator/stryker-net#3117).
  • Loading branch information
vbreuss authored Jan 25, 2025
1 parent 580969d commit 6656062
Show file tree
Hide file tree
Showing 244 changed files with 2,313 additions and 2,294 deletions.
42 changes: 0 additions & 42 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,48 +67,6 @@ jobs:
./Artifacts/*
./TestResults/*.trx
mutation-tests-linux:
name: "Mutation tests (Linux)"
if: ${{ github.actor != 'dependabot[bot]' }}
runs-on: ubuntu-latest
env:
STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }}
DOTNET_NOLOGO: true
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET SDKs
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
6.0.x
8.0.x
9.0.x
- name: Run mutation tests
run: ./build.sh MutationTestsLinux

mutation-tests-windows:
name: "Mutation tests (Windows)"
if: ${{ github.actor != 'dependabot[bot]' }}
runs-on: windows-latest
env:
STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }}
DOTNET_NOLOGO: true
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET SDKs
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
6.0.x
8.0.x
9.0.x
- name: Run mutation tests
run: ./build.ps1 MutationTestsWindows

static-code-analysis:
name: "Static code analysis"
runs-on: ubuntu-latest
Expand Down
1 change: 0 additions & 1 deletion .nuke/build.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
"CodeAnalysisEnd",
"CodeCoverage",
"Compile",
"DotNetFrameworkUnitTests",
"DotNetUnitTests",
"MutationComment",
"MutationTestPreparation",
Expand Down
9 changes: 4 additions & 5 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,14 @@
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.1"/>
</ItemGroup>
<ItemGroup>
<PackageVersion Include="AutoFixture.AutoNSubstitute" Version="4.18.1"/>
<PackageVersion Include="AutoFixture.Xunit2" Version="4.18.1"/>
<PackageVersion Include="AutoFixture.AutoNSubstitute" Version="5.0.0-preview0012"/>
<PackageVersion Include="AutoFixture.Xunit3" Version="5.0.0-preview0012"/>
<PackageVersion Include="aweXpect" Version="0.17.0"/>
<PackageVersion Include="aweXpect.Testably" Version="0.3.0"/>
<PackageVersion Include="FluentAssertions" Version="7.0.0"/>
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0"/>
<PackageVersion Include="Xunit.SkippableFact" Version="1.5.23"/>
<PackageVersion Include="xunit" Version="2.9.3"/>
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2"/>
<PackageVersion Include="xunit.v3" Version="1.0.1"/>
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.1"/>
<PackageVersion Include="coverlet.collector" Version="6.0.4"/>
<PackageVersion Include="PublicApiGenerator" Version="11.3.0"/>
<PackageVersion Include="NUnit" Version="4.3.2"/>
Expand Down
2 changes: 1 addition & 1 deletion Pipeline/Build.Compile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ partial class Build
{
SemVer = GitVersion?.SemVer;

if (GitHubActions.IsPullRequest && GitVersion != null)
if (GitHubActions?.IsPullRequest == true && GitVersion != null)
{
string buildNumber = GitHubActions.RunNumber.ToString();
Console.WriteLine(
Expand Down
50 changes: 5 additions & 45 deletions Pipeline/Build.UnitTest.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
using Nuke.Common;
using Nuke.Common.IO;
using Nuke.Common.ProjectModel;
using Nuke.Common.Tooling;
using Nuke.Common.Tools.DotNet;
using Nuke.Common.Tools.Xunit;
using Serilog;
using System;
using System.Linq;
using static Nuke.Common.Tools.Xunit.XunitTasks;
using static Nuke.Common.Tools.DotNet.DotNetTasks;

// ReSharper disable AllUnderscoreLocalParameterName
Expand All @@ -18,51 +15,15 @@ partial class Build
{
const int MaxRetries = 1;

Target DotNetFrameworkUnitTests => _ => _
.Unlisted()
.DependsOn(Compile)
.OnlyWhenDynamic(() => EnvironmentInfo.IsWin)
.Executes(() =>
{
string[] testAssemblies = UnitTestProjects
.SelectMany(project =>
project.Directory.GlobFiles(
$"bin/{(Configuration == Configuration.Debug ? "Debug" : "Release")}/net48/*.Tests.dll"))
.Select(p => p.ToString())
.ToArray();

Assert.NotEmpty(testAssemblies.ToList());

string net48 = "net48";
for (int retry = MaxRetries; retry >= 0; retry--)
{
try
{
Xunit2(s => s
.SetFramework(net48)
.AddTargetAssemblies(testAssemblies)
);
}
catch (Exception ex)
{
if (retry == 0)
{
Log.Error($"All {MaxRetries + 1} tries failed: {ex}");
throw;
}

Log.Error($"Error during unit tests: {ex}");
Log.Information($"Retry {MaxRetries - retry + 1} of {MaxRetries} times:");
}
}
});

Target DotNetUnitTests => _ => _
.Unlisted()
.DependsOn(Compile)
.Executes(() =>
{
string net48 = "net48";
string[] excludedFrameworks =
EnvironmentInfo.IsWin
? []
: ["net48"];
for (int retry = MaxRetries; retry >= 0; retry--)
{
try
Expand All @@ -78,7 +39,7 @@ partial class Build
(settings, project) => settings
.SetProjectFile(project)
.CombineWith(
project.GetTargetFrameworks()?.Except([net48]),
project.GetTargetFrameworks()?.Except(excludedFrameworks),
(frameworkSettings, framework) => frameworkSettings
.SetFramework(framework)
.AddLoggers(
Expand Down Expand Up @@ -111,6 +72,5 @@ partial class Build
];

Target UnitTests => _ => _
.DependsOn(DotNetFrameworkUnitTests)
.DependsOn(DotNetUnitTests);
}
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
[![Build](https://github.com/Testably/Testably.Abstractions/actions/workflows/build.yml/badge.svg)](https://github.com/Testably/Testably.Abstractions/actions/workflows/build.yml)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Testably_Testably.Abstractions&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=Testably_Testably.Abstractions)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=Testably_Testably.Abstractions&metric=coverage)](https://sonarcloud.io/summary/new_code?id=Testably_Testably.Abstractions)
[![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.jparrowsec.cn%2FTestably%2FTestably.Abstractions%2Fmain)](https://dashboard.stryker-mutator.io/reports/github.com/Testably/Testably.Abstractions/main)

This library is a feature complete testing helper for the [IFileSystem abstractions for I/O-related functionality](https://github.com/TestableIO/System.IO.Abstractions) from the `System.IO` namespace. It uses an in-memory file system that behaves exactly like the real file system and can be used in unit tests for dependency injection.
The testing helper also supports advanced scenarios like
Expand Down
6 changes: 3 additions & 3 deletions Tests/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<OutputType>Exe</OutputType>
<NoWarn>$(NoWarn);701;1702;CA1845;MA0003;MA0004;MA0018;MA0020;MA0042;MA0076;xUnit1044;xUnit1045;NU1603</NoWarn>
</PropertyGroup>

Expand All @@ -25,10 +26,9 @@
<ItemGroup>
<PackageReference Include="aweXpect" />
<PackageReference Include="aweXpect.Testably" />
<PackageReference Include="AutoFixture.Xunit2" />
<PackageReference Include="AutoFixture.Xunit3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Xunit.SkippableFact" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.v3" />
<PackageReference Include="xunit.runner.visualstudio">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using AutoFixture;
using AutoFixture.Xunit2;
using AutoFixture.Xunit3;
using AutoFixture.AutoNSubstitute;
using System;
using System.Linq;
Expand All @@ -13,16 +13,16 @@ namespace Testably.Abstractions.TestHelpers;
public class AutoDomainDataAttribute : AutoDataAttribute
{
private Type? _customizeWith;
private readonly FixtureFactory _fixtureFactory;
private readonly DomainFixtureFactory _fixtureFactory;

/// <summary>
/// Extension of <see cref="AutoDataAttribute"/> that uses applies domain-specific customizations.
/// </summary>
public AutoDomainDataAttribute() : this(new FixtureFactory())
public AutoDomainDataAttribute() : this(new DomainFixtureFactory())
{
}

private AutoDomainDataAttribute(FixtureFactory fixtureFactory)
private AutoDomainDataAttribute(DomainFixtureFactory fixtureFactory)
: base(fixtureFactory.GetFixtureFactory)
{
_fixtureFactory = fixtureFactory;
Expand All @@ -44,7 +44,7 @@ public Type? CustomizeWith
}
}

private sealed class FixtureFactory
private sealed class DomainFixtureFactory
{
private ICustomization? _customizeWith;
private static Lazy<ICustomization[]> _domainCustomisation { get; } = new(Initialize);
Expand Down
53 changes: 53 additions & 0 deletions Tests/Helpers/Testably.Abstractions.TestHelpers/Skip.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Runtime.CompilerServices;

namespace Testably.Abstractions.TestHelpers
{

public static class Skip
{
public static void IfNot(bool condition,
[CallerArgumentExpression("condition")] string reason = "")
{
aweXpect.Skip.Unless(condition, reason);
}

public static void If(bool condition,
[CallerArgumentExpression("condition")] string reason = "")
{
aweXpect.Skip.When(condition, reason);
}
}
}

#if !NET6_0_OR_GREATER

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// ReSharper disable once CheckNamespace
namespace System.Runtime.CompilerServices
{
/// <summary>
/// Indicates that a parameter captures the expression passed for another parameter as a string.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal sealed class CallerArgumentExpressionAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="CallerArgumentExpressionAttribute" /> class.
/// </summary>
/// <param name="parameterName">The name of the parameter whose expression should be captured as a string.</param>
public CallerArgumentExpressionAttribute(string parameterName)
{
ParameterName = parameterName;
}

/// <summary>
/// Gets the name of the parameter whose expression should be captured as a string.
/// </summary>
public string ParameterName { get; }
}
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<PropertyGroup>
<TargetFrameworks>$(TargetFrameworks);netstandard2.0</TargetFrameworks>
<IsTestProject>false</IsTestProject>
<OutputType>Library</OutputType>
</PropertyGroup>

<ItemGroup>
Expand All @@ -18,7 +19,7 @@
<PackageReference Include="FluentAssertions" />
<PackageReference Include="AutoFixture.AutoNSubstitute" />
<PackageReference Remove="Microsoft.NET.Test.Sdk" />
<PackageReference Remove="xunit" />
<PackageReference Remove="xunit.v3" />
<PackageReference Remove="xunit.runner.visualstudio" />
<PackageReference Remove="coverlet.collector" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ public static string GenerateFileSystemTestClasses(ClassModel model)
using Testably.Abstractions.Testing.Initializer;
using Testably.Abstractions.TestHelpers;
using Testably.Abstractions.TestHelpers.Settings;
using Xunit.Abstractions;
namespace {{model.Namespace}}
{
Expand Down Expand Up @@ -116,12 +115,12 @@ public RealFileSystemTests(ITestOutputHelper testOutputHelper, TestSettingsFixtu
#if DEBUG
if (fixture.RealFileSystemTests != TestSettingStatus.AlwaysEnabled)
{
throw new Xunit.SkipException($"Tests against the real file system are {fixture.RealFileSystemTests}. You can enable them by executing the corresponding tests in Testably.Abstractions.TestSettings.RealFileSystemTests.");
aweXpect.Skip.Test($"Tests against the real file system are {fixture.RealFileSystemTests}. You can enable them by executing the corresponding tests in Testably.Abstractions.TestSettings.RealFileSystemTests.");
}
#else
if (fixture.RealFileSystemTests == TestSettingStatus.AlwaysDisabled)
{
throw new Xunit.SkipException($"Tests against the real file system are {fixture.RealFileSystemTests}. You can enable them by executing the corresponding tests in Testably.Abstractions.TestSettings.RealFileSystemTests.");
aweXpect.Skip.Test($"Tests against the real file system are {fixture.RealFileSystemTests}. You can enable them by executing the corresponding tests in Testably.Abstractions.TestSettings.RealFileSystemTests.");
}
#endif
_fixture = fixture;
Expand All @@ -136,24 +135,24 @@ public void Dispose()
#if DEBUG
/// <inheritdoc cref="{{model.Name}}.SkipIfBrittleTestsShouldBeSkipped(bool)" />
public override void SkipIfBrittleTestsShouldBeSkipped(bool condition = true)
=> Xunit.Skip.If(condition && _fixture.BrittleTests != TestSettingStatus.AlwaysEnabled,
=> aweXpect.Skip.When(condition && _fixture.BrittleTests != TestSettingStatus.AlwaysEnabled,
$"Brittle tests are {_fixture.BrittleTests}. You can enable them by executing the corresponding tests in Testably.Abstractions.TestSettings.BrittleTests.");
#else
/// <inheritdoc cref="{{model.Name}}.SkipIfBrittleTestsShouldBeSkipped(bool)" />
public override void SkipIfBrittleTestsShouldBeSkipped(bool condition = true)
=> Xunit.Skip.If(condition && _fixture.BrittleTests == TestSettingStatus.AlwaysDisabled,
=> aweXpect.Skip.When(condition && _fixture.BrittleTests == TestSettingStatus.AlwaysDisabled,
$"Brittle tests are {_fixture.BrittleTests}. You can enable them by executing the corresponding tests in Testably.Abstractions.TestSettings.BrittleTests.");
#endif
#if DEBUG
/// <inheritdoc cref="{{model.Name}}.LongRunningTestsShouldBeSkipped()" />
public override void SkipIfLongRunningTestsShouldBeSkipped()
=> Xunit.Skip.If(_fixture.LongRunningTests != TestSettingStatus.AlwaysEnabled,
=> aweXpect.Skip.When(_fixture.LongRunningTests != TestSettingStatus.AlwaysEnabled,
$"Long-running tests are {_fixture.LongRunningTests}. You can enable them by executing the corresponding tests in Testably.Abstractions.TestSettings.LongRunningTests.");
#else
/// <inheritdoc cref="{{model.Name}}.LongRunningTestsShouldBeSkipped()" />
public override void SkipIfLongRunningTestsShouldBeSkipped()
=> Xunit.Skip.If(_fixture.LongRunningTests == TestSettingStatus.AlwaysDisabled,
=> aweXpect.Skip.When(_fixture.LongRunningTests == TestSettingStatus.AlwaysDisabled,
$"Long-running tests are {_fixture.LongRunningTests}. You can enable them by executing the corresponding tests in Testably.Abstractions.TestSettings.LongRunningTests.");
#endif
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ public static string GenerateRandomSystemTestClasses(ClassModel model)
StringBuilder? sb = GetSourceBuilder();
sb.AppendLine($$"""
using Testably.Abstractions.TestHelpers;
using Xunit.Abstractions;
namespace {{model.Namespace}}
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public static string GenerateTimeSystemTestClasses(ClassModel model)
sb.AppendLine($$"""
using Testably.Abstractions.TestHelpers;
using Testably.Abstractions.TestHelpers.Settings;
using Xunit.Abstractions;
namespace {{model.Namespace}}
{
Expand Down Expand Up @@ -77,12 +76,12 @@ public RealTimeSystemTests(TestSettingsFixture fixture) : base(new RealTimeSyste
#if DEBUG
/// <inheritdoc cref="{{model.Name}}.SkipIfBrittleTestsShouldBeSkipped(bool)" />
public override void SkipIfBrittleTestsShouldBeSkipped(bool condition = true)
=> Xunit.Skip.If(condition && _fixture.BrittleTests != TestSettingStatus.AlwaysEnabled,
=> aweXpect.Skip.When(condition && _fixture.BrittleTests != TestSettingStatus.AlwaysEnabled,
$"Brittle tests are {_fixture.BrittleTests}. You can enable them by executing the corresponding tests in Testably.Abstractions.TestSettings.BrittleTests.");
#else
/// <inheritdoc cref="{{model.Name}}.SkipIfBrittleTestsShouldBeSkipped(bool)" />
public override void SkipIfBrittleTestsShouldBeSkipped(bool condition = true)
=> Xunit.Skip.If(condition && _fixture.BrittleTests == TestSettingStatus.AlwaysDisabled,
=> aweXpect.Skip.When(condition && _fixture.BrittleTests == TestSettingStatus.AlwaysDisabled,
$"Brittle tests are {_fixture.BrittleTests}. You can enable them by executing the corresponding tests in Testably.Abstractions.TestSettings.BrittleTests.");
#endif
}
Expand Down
Loading

0 comments on commit 6656062

Please sign in to comment.