Skip to content

Commit da39b20

Browse files
authored
Refactors UI test setup and updates dependencies (#4058)
* Refactors UI test setup to use TUnit executor Centralizes remote app startup and test recorder management in XamlTestExecutor, removing boilerplate from individual tests; marks long-running tests as explicit and enables TUnit parallel limiting. * Updates dependencies and refactors test utilities Upgrades core packages including TUnit, System.CommandLine, and XAMLTest. Refactors `CommandLineOptions` for `System.CommandLine` API updates. Adapts TUnit assertion extensions and test execution context usage. Adds `ModuleInitializerAttribute` for NET472 support. * Refine test infrastructure and code quality Removes explicit `recorder.Success()` calls from UI tests, completing the centralization of test recorder management introduced by the `XamlTestExecutor` refactor. Cleans up unused package versions and test dependencies. Addresses nullable warnings and removes Byte Order Mark (BOM) for improved code hygiene.
1 parent 5ee1c9d commit da39b20

48 files changed

Lines changed: 281 additions & 942 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build_artifacts.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848

4949
- name: Test
5050
timeout-minutes: 20
51-
run: dotnet test ${{ env.solution }} --configuration ${{ inputs.build-configuration }} --no-build --blame-crash --logger GitHubActions
51+
run: dotnet test ${{ env.solution }} --configuration ${{ inputs.build-configuration }} --no-build
5252

5353
- name: Upload Screenshots
5454
if: ${{ always() }}

Directory.packages.props

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44
<!-- https://learn.microsoft.com/nuget/consume-packages/Central-Package-Management?WT.mc_id=DT-MVP-5003472#transitive-pinning -->
55
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
66
</PropertyGroup>
7-
87
<ItemGroup>
98
<PackageVersion Include="BluwolfIcons" Version="1.0.1" />
109
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0" />
1110
<PackageVersion Include="Dragablz" Version="0.0.3.234" />
12-
<PackageVersion Include="GitHubActionsTestLogger" Version="2.4.1" />
11+
<PackageVersion Include="GitHubActionsTestLogger" Version="3.0.1" />
1312
<PackageVersion Include="Humanizer" Version="2.14.1" />
1413
<PackageVersion Include="MahApps.Metro" Version="2.4.11" />
1514
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="6.0.0" />
@@ -21,7 +20,7 @@
2120
<PackageVersion Include="Microsoft.Composition" Version="1.0.31" />
2221
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
2322
<PackageVersion Include="Microsoft.NETCore.Platforms" Version="7.0.4" />
24-
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
23+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
2524
<PackageVersion Include="Microsoft.Toolkit.MVVM" Version="7.1.2" />
2625
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
2726
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
@@ -32,9 +31,11 @@
3231
<PackageVersion Include="ShowMeTheXAML.MSBuild" Version="2.0.0" />
3332
<PackageVersion Include="System.CommandLine" Version="2.0.2" />
3433
<PackageVersion Include="System.Memory" Version="4.6.3" />
34+
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
3535
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
3636
<PackageVersion Include="System.ValueTuple" Version="4.6.1" />
37-
<PackageVersion Include="TUnit" Version="0.25.21" />
37+
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
38+
<PackageVersion Include="TUnit" Version="1.9.45" />
3839
<PackageVersion Include="VirtualizingWrapPanel" Version="1.5.8" />
3940
<PackageVersion Include="XAMLTest" Version="1.3.1-ci662" />
4041
</ItemGroup>

global.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
{
2-
"sdk": {
3-
"version": "10.0.102",
4-
"rollForward": "latestMinor"
5-
}
2+
"sdk": {
3+
"version": "10.0.102",
4+
"rollForward": "latestMinor"
5+
},
6+
"test": {
7+
"runner": "Microsoft.Testing.Platform"
8+
}
69
}

tests/MaterialColorUtilities.Tests/HctTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
public sealed class HctTests
44
{
55
[Test]
6-
[Skip("Takes a long time to run")]
6+
[Explicit] //Takes a long time to run
77
[DisplayName("HCT preserves original color for all opaque ARGB values")]
88
public async Task Hct_Preserves_Original_Color_For_All_Opaque_ARGB()
99
{

tests/MaterialColorUtilities.Tests/MaterialColorUtilities.Tests.csproj

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,7 @@
22
<Project Sdk="Microsoft.NET.Sdk">
33
<PropertyGroup>
44
<TargetFrameworks>net8.0-windows;net10.0-windows</TargetFrameworks>
5-
<AssemblyTitle>MaterialColorUtilities.Tests</AssemblyTitle>
6-
<Product>MaterialColorUtilities.Tests</Product>
75
<OutputType>Exe</OutputType>
8-
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
9-
<TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
106
<UseWPF>true</UseWPF>
117
<ImplicitUsings>enable</ImplicitUsings>
128
<Nullable>enable</Nullable>
@@ -18,16 +14,11 @@
1814
<ProjectReference Include="..\..\src\MaterialDesign3.MaterialColorUtilities\MaterialColorUtilities.csproj" />
1915
</ItemGroup>
2016
<ItemGroup>
21-
<PackageReference Include="GitHubActionsTestLogger">
22-
<PrivateAssets>all</PrivateAssets>
23-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
24-
</PackageReference>
2517
<PackageReference Include="Microsoft.NET.Test.Sdk" />
2618
<PackageReference Include="TUnit" />
2719
<PackageReference Include="Shouldly" />
2820
</ItemGroup>
2921
<ItemGroup>
30-
<Using Include="TUnit.Assertions.AssertConditions.Throws" />
3122
<Using Include="TUnit.Core.Executors" />
3223
<Using Include="TUnit.Assertions" />
3324
<Using Include="Shouldly" />
Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1-
<?xml version="1.0" encoding="utf-8"?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<Project Sdk="Microsoft.NET.Sdk">
33
<PropertyGroup>
44
<TargetFrameworks>net472;net8.0-windows;net10.0-windows</TargetFrameworks>
5-
<AssemblyTitle>MaterialDesignColors.Wpf.Tests</AssemblyTitle>
6-
<Product>MaterialDesignColors.Wpf.Tests</Product>
7-
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
85
<OutputType>Exe</OutputType>
9-
<TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
106
</PropertyGroup>
117
<ItemGroup Condition="'$(TargetFramework)'=='net472'">
128
<Reference Include="PresentationCore" />
@@ -24,11 +20,7 @@
2420
<ProjectReference Include="..\..\src\MaterialDesignColors.Wpf\MaterialDesignColors.Wpf.csproj" />
2521
</ItemGroup>
2622
<ItemGroup>
27-
<PackageReference Include="GitHubActionsTestLogger">
28-
<PrivateAssets>all</PrivateAssets>
29-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
30-
</PackageReference>
3123
<PackageReference Include="System.Private.Uri" />
3224
<PackageReference Include="TUnit" />
3325
</ItemGroup>
34-
</Project>
26+
</Project>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#if NET472
2+
namespace System.Runtime.CompilerServices;
3+
4+
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
5+
internal sealed class ModuleInitializerAttribute : Attribute
6+
{
7+
}
8+
#endif

tests/MaterialDesignThemes.UITests/AllStyles.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ public class AllStyles : TestBase
3232
[Arguments("TreeView", "MaterialDesignTreeView")]
3333
public async Task LoadStyleInIsolation_CanBeLoaded(string controlName, string styleName)
3434
{
35-
await using var recorder = new TestRecorder(App);
36-
3735
string applicationResourceXaml = $$"""
3836
<ResourceDictionary
3937
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
@@ -78,7 +76,5 @@ await App.Initialize(applicationResourceXaml,
7876
""");
7977

8078
await Assert.That(await window.GetIsVisible()).IsTrue();
81-
82-
recorder.Success();
8379
}
8480
}

tests/MaterialDesignThemes.UITests/MaterialDesignThemes.UITests.csproj

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,12 @@
66
<UseWPF>true</UseWPF>
77
<NoWarn>$(NoWarn);CA1707</NoWarn>
88
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
9-
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
109
<OutputType>Exe</OutputType>
11-
<TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
1210
<!--<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>-->
1311
</PropertyGroup>
1412

1513
<ItemGroup>
1614
<PackageReference Include="CommunityToolkit.Mvvm" />
17-
<PackageReference Include="GitHubActionsTestLogger">
18-
<PrivateAssets>all</PrivateAssets>
19-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
20-
</PackageReference>
2115
<PackageReference Include="Microsoft.NET.Test.Sdk" />
2216
<PackageReference Include="XAMLTest" />
2317
<PackageReference Include="TUnit" />
@@ -32,4 +26,4 @@
3226
<ItemGroup>
3327
<ProjectReference Include="..\..\src\MaterialDesignThemes.Wpf\MaterialDesignThemes.Wpf.csproj" />
3428
</ItemGroup>
35-
</Project>
29+
</Project>
Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,72 @@
11
using System.Numerics;
22
using System.Runtime.CompilerServices;
3-
using TUnit.Assertions.AssertConditions;
4-
using TUnit.Assertions.AssertConditions.Interfaces;
5-
using TUnit.Assertions.AssertionBuilders;
3+
using TUnit.Assertions.Core;
64

75
namespace MaterialDesignThemes.Tests.TUnit;
86

97
public static class IsCloseToExtensions
108
{
11-
public static IsCloseToWrapper<double> IsCloseTo(this IValueSource<double> valueSource, double expected, double precision, [CallerArgumentExpression(nameof(expected))] string? doNotPopulateThisValue1 = null, [CallerArgumentExpression(nameof(precision))] string? doNotPopulateThisValue2 = null)
9+
public static IsCloseToAssertion<double> IsCloseTo(
10+
this IAssertionSource<double> source, double expected, double precision,
11+
[CallerArgumentExpression(nameof(expected))] string? expectedExpression = null,
12+
[CallerArgumentExpression(nameof(precision))] string? precisionExpression = null)
1213
{
13-
var assertionBuilder = valueSource.RegisterAssertion(new IsCloseToCondition<double>(expected, precision)
14-
, [doNotPopulateThisValue1, doNotPopulateThisValue2]);
15-
16-
return new IsCloseToWrapper<double>(assertionBuilder);
14+
source.Context.ExpressionBuilder.Append(".IsCloseTo(");
15+
source.Context.ExpressionBuilder.Append(expectedExpression);
16+
source.Context.ExpressionBuilder.Append(", ");
17+
source.Context.ExpressionBuilder.Append(precisionExpression);
18+
source.Context.ExpressionBuilder.Append(')');
19+
return new IsCloseToAssertion<double>(source.Context, expected, precision);
1720
}
1821

19-
public static IsCloseToWrapper<float> IsCloseTo(this IValueSource<float> valueSource, float expected, float precision, [CallerArgumentExpression(nameof(expected))] string? doNotPopulateThisValue1 = null, [CallerArgumentExpression(nameof(precision))] string? doNotPopulateThisValue2 = null)
22+
public static IsCloseToAssertion<float> IsCloseTo(
23+
this IAssertionSource<float> source, float expected, float precision,
24+
[CallerArgumentExpression(nameof(expected))] string? expectedExpression = null,
25+
[CallerArgumentExpression(nameof(precision))] string? precisionExpression = null)
2026
{
21-
var assertionBuilder = valueSource.RegisterAssertion(new IsCloseToCondition<float>(expected, precision)
22-
, [doNotPopulateThisValue1, doNotPopulateThisValue2]);
23-
24-
return new IsCloseToWrapper<float>(assertionBuilder);
27+
source.Context.ExpressionBuilder.Append(".IsCloseTo(");
28+
source.Context.ExpressionBuilder.Append(expectedExpression);
29+
source.Context.ExpressionBuilder.Append(", ");
30+
source.Context.ExpressionBuilder.Append(precisionExpression);
31+
source.Context.ExpressionBuilder.Append(')');
32+
return new IsCloseToAssertion<float>(source.Context, expected, precision);
2533
}
2634
}
2735

28-
public class IsCloseToWrapper<TActual>(InvokableAssertionBuilder<TActual> invokableAssertionBuilder)
29-
: InvokableValueAssertionBuilder<TActual>(invokableAssertionBuilder);
30-
31-
file class IsCloseToCondition<TActual>(TActual expected, TActual tolerance) : BaseAssertCondition<TActual>
32-
where TActual :
33-
IFloatingPoint<TActual>,
34-
INumberBase<TActual>
36+
public class IsCloseToAssertion<TValue>(AssertionContext<TValue> context, TValue expected, TValue precision) : Assertion<TValue>(context)
37+
where TValue : IFloatingPoint<TValue>, INumberBase<TValue>
3538
{
36-
protected override string GetExpectation() => $"to be within {tolerance} of {expected}";
39+
protected override string GetExpectation()
40+
{
41+
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new(15, 1);
42+
defaultInterpolatedStringHandler.AppendLiteral("to be within ");
43+
defaultInterpolatedStringHandler.AppendFormatted($"\"{precision}\"");
44+
defaultInterpolatedStringHandler.AppendLiteral(" of ");
45+
defaultInterpolatedStringHandler.AppendFormatted($"\"{expected}\"");
46+
return defaultInterpolatedStringHandler.ToStringAndClear();
47+
}
3748

38-
protected override ValueTask<AssertionResult> GetResult(
39-
TActual? actualValue, Exception? exception,
40-
AssertionMetadata assertionMetadata
41-
)
49+
protected override Task<AssertionResult> CheckAsync(EvaluationMetadata<TValue> metadata)
4250
{
43-
if(actualValue is null)
44-
return AssertionResult.Fail("received null");
51+
TValue? actualValue = metadata.Value;
52+
Exception? exception = metadata.Exception;
53+
if (exception != null)
54+
{
55+
return Task.FromResult(AssertionResult.Failed("threw " + exception.GetType().FullName));
56+
}
57+
if (actualValue is null)
58+
{
59+
return Task.FromResult(AssertionResult.Failed($"found <null>"));
60+
}
61+
62+
TValue difference = actualValue - expected;
63+
TValue absoluteDifference = TValue.Abs(difference);
64+
bool isInRange = absoluteDifference <= precision;
4565

46-
TActual difference = actualValue - expected;
47-
TActual absoluteDifference = TActual.Abs(difference);
48-
bool isInRange = absoluteDifference <= tolerance;
49-
return AssertionResult.FailIf(!isInRange, $"received {actualValue}");
66+
if (isInRange)
67+
{
68+
return Task.FromResult(AssertionResult.Passed);
69+
}
70+
return Task.FromResult(AssertionResult.Failed($"found {actualValue}"));
5071
}
5172
}

0 commit comments

Comments
 (0)