Skip to content
3 changes: 3 additions & 0 deletions src/Microsoft.DotNet.Arcade.Sdk/tools/DefaultVersions.props
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@
<XUnitRunnerConsoleVersion Condition="'$(XUnitRunnerConsoleVersion)' == ''">$(XUnitVersion)</XUnitRunnerConsoleVersion>
<XUnitRunnerVisualStudioVersion Condition="'$(XUnitRunnerVisualStudioVersion)' == ''">3.0.2</XUnitRunnerVisualStudioVersion>

<XUnitV3Version Condition="'$(XUnitV3Version)' == ''">2.0.0</XUnitV3Version>
<MicrosoftTestingPlatformVersion Condition="'$(MicrosoftTestingPlatformVersion)' == ''">1.6.3</MicrosoftTestingPlatformVersion>

<MSTestVersion Condition="'$(MSTestVersion)' == ''">3.8.3</MSTestVersion>
<MSTestTestAdapterVersion Condition="'$(MSTestTestAdapterVersion)' == ''">$(MSTestVersion)</MSTestTestAdapterVersion>
<MSTestTestFrameworkVersion Condition="'$(MSTestTestFrameworkVersion)' == ''">$(MSTestVersion)</MSTestTestFrameworkVersion>
Expand Down
5 changes: 4 additions & 1 deletion src/Microsoft.DotNet.Arcade.Sdk/tools/Tests.props
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>

<ItemGroup Condition="'$(IsTestProject)' == 'true' and '$(ExcludeMicrosoftNetTestSdk)' != 'true'">
<!-- Microsoft.NET.Test.Sdk is VSTest-specific package. -->
<!-- If EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner is true, then the repo is using Microsoft.Testing.Platform -->
Comment on lines +32 to +33
Copy link
Member Author

@Youssef1313 Youssef1313 Mar 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is technically breaking.

If a repo is setting EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner but is not either opting-in via dotnet.config or TestingPlatformCommandLineArguments, then their setup will actually be using VSTest when invoking dotnet test directly.

This also means that such repos are not properly configured to use MTP, where the intent may be to use it. So I think it may be reasonable to break, but I'll let you decide.

<!-- In that case, we don't need Microsoft.NET.Test.Sdk -->
<ItemGroup Condition="'$(IsTestProject)' == 'true' and '$(ExcludeMicrosoftNetTestSdk)' != 'true' and '$(EnableMSTestRunner)' != 'true' and '$(EnableNUnitRunner)' != 'true' and '$(UseMicrosoftTestingPlatformRunner)' != 'true'">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkVersion)" IsImplicitlyDefined="true" />
</ItemGroup>

Expand Down
3 changes: 3 additions & 0 deletions src/Microsoft.DotNet.Arcade.Sdk/tools/Tests.targets
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
<Target Name="_InnerGetTestsToRun"
Outputs="%(_TestArchitectureItems.Identity)"
Returns="@(TestToRun)"
DependsOnTargets="ComputeRunArguments"
Condition="'$(TestRuntime)' != '' and '$(SkipTests)' != 'true' and
('$(TestTargetFrameworks)' == '' or $([System.String]::new(';$(TestTargetFrameworks);').Contains(';$(TargetFramework);')))">

Expand Down Expand Up @@ -71,6 +72,8 @@
<ResultsStdOutPath>$(TestResultsLogDir)$(_ResultFileNameNoExt).log</ResultsStdOutPath>
<TestRunSettingsFile>$(TestRunSettingsFile)</TestRunSettingsFile>
<TestRunnerAdditionalArguments>$(TestRunnerAdditionalArguments)</TestRunnerAdditionalArguments>
<RunArguments>$(RunArguments)</RunArguments>
<RunCommand>$(RunCommand)</RunCommand>
</TestToRun>
</ItemGroup>
</Target>
Expand Down
3 changes: 3 additions & 0 deletions src/Microsoft.DotNet.Arcade.Sdk/tools/VSTest.targets
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
<Target Name="RunTests"
Outputs="%(TestToRun.ResultsStdOutPath)"
Condition="'$(SkipTests)' != 'true' and '@(TestToRun)' != ''">

<Error Text="UseVSTest shouldn't be used when using Microsoft.Testing.Platform" Condition="'$(EnableMSTestRunner)' == 'true' OR '$(EnableNUnitRunner)' == 'true' OR '$(UseMicrosoftTestingPlatformRunner)' == 'true'" File="VSTest" />

<PropertyGroup>
<_TestEnvironment>%(TestToRun.EnvironmentDisplay)</_TestEnvironment>
<_TestAssembly>%(TestToRun.Identity)</_TestAssembly>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. -->
<Project>

<Target Name="RunTests"
Outputs="%(TestToRun.ResultsStdOutPath)"
Condition="'@(TestToRun)' != ''">
<Telemetry EventName="NETCORE_ENGINEERING_TELEMETRY" EventData="Category=Test" />

<PropertyGroup Condition="'$(UseMicrosoftTestingPlatformRunner)' == 'true'">
<_TestResultDirectory>$([System.IO.Path]::GetDirectoryName('%(TestToRun.ResultsTrxPath)'))</_TestResultDirectory>
<_TestResultTrxFileName>$([System.IO.Path]::GetFileName('%(TestToRun.ResultsTrxPath)'))</_TestResultTrxFileName>
<_TestResultXmlFileName>$([System.IO.Path]::GetFileName('%(TestToRun.ResultsXmlPath)'))</_TestResultXmlFileName>
<_TestResultHtmlFileName>$([System.IO.Path]::GetFileName('%(TestToRun.ResultsHtmlPath)'))</_TestResultHtmlFileName>
</PropertyGroup>

<PropertyGroup>
<_TestEnvironment>%(TestToRun.EnvironmentDisplay)</_TestEnvironment>
<_TestAssembly>%(TestToRun.Identity)</_TestAssembly>
<_TestRuntime>%(TestToRun.TestRuntime)</_TestRuntime>
<_TestTimeout>%(TestToRun.TestTimeout)</_TestTimeout>
<_TestRunnerAdditionalArguments>%(TestToRun.TestRunnerAdditionalArguments)</_TestRunnerAdditionalArguments>

<_TestRunner>%(TestToRun.RunCommand)</_TestRunner>
<_TestRunnerArgs Condition="'$(UseMicrosoftTestingPlatformRunner)' != 'true'">%(TestToRun.RunArguments) $(_TestRunnerAdditionalArguments) -xml "%(TestToRun.ResultsXmlPath)" -html "%(TestToRun.ResultsHtmlPath)" -trx "%(TestToRun.ResultsTrxPath)"</_TestRunnerArgs>
<_TestRunnerArgs Condition="'$(UseMicrosoftTestingPlatformRunner)' == 'true'">%(TestToRun.RunArguments) $(_TestRunnerAdditionalArguments) --results-directory "$(_TestResultDirectory)" --report-xunit --report-xunit-filename "$(_TestResultXmlFileName)" --report-xunit-html --report-xunit-html-filename "$(_TestResultHtmlFileName)" --report-trx --report-trx-filename "$(_TestResultTrxFileName)"</_TestRunnerArgs>

<TestDotNetRoot Condition="'$(TestDotNetRoot)' == ''">$(DotNetRoot)</TestDotNetRoot>
</PropertyGroup>

<PropertyGroup Condition="'$(_TestRuntime)' == 'Core'">
<_TestRunnerArgs Condition="'$(UseMicrosoftTestingPlatformRunner)' != 'true'">$(_TestRunnerArgs) -noAutoReporters</_TestRunnerArgs>
<_TestRunnerArgs Condition="'$(UseMicrosoftTestingPlatformRunner)' == 'true'">$(_TestRunnerArgs) --auto-reporters off</_TestRunnerArgs>
</PropertyGroup>
Comment on lines +30 to +33
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using the same '$(_TestRuntime)' == 'Core' condition as in xunit v2. But I'm not following why this only applies for .NET Core


<PropertyGroup>
<_TestRunnerCommand>"$(_TestRunner)" $(_TestRunnerArgs)</_TestRunnerCommand>

<!--
Redirect std output of the runner.
Note that xUnit outputs failure info to both STDOUT (stack trace, message) and STDERR (failed test name)
-->
<_TestRunnerCommand Condition="'$(TestCaptureOutput)' != 'false'">$(_TestRunnerCommand) >> "%(TestToRun.ResultsStdOutPath)" 2>&amp;1</_TestRunnerCommand>
</PropertyGroup>

<ItemGroup>
<_OutputFiles Include="%(TestToRun.ResultsXmlPath)" />
<_OutputFiles Include="%(TestToRun.ResultsHtmlPath)" />
<_OutputFiles Include="%(TestToRun.ResultsStdOutPath)" />
</ItemGroup>

<MakeDir Directories="@(_OutputFiles->'%(RootDir)%(Directory)')"/>
<Delete Files="@(_OutputFiles)" />

<Message Text="Running tests: $(_TestAssembly) [$(_TestEnvironment)]" Importance="high"/>

<!--
Add command line to the log.
-->
<Exec Command="echo === COMMAND LINE === > %(TestToRun.ResultsStdOutPath)
echo $(_TestRunnerCommand) >> %(TestToRun.ResultsStdOutPath)" />

<Exec Command='$(_TestRunnerCommand)'
LogStandardErrorAsError="false"
WorkingDirectory="$(_TargetDir)"
IgnoreExitCode="true"
Timeout="$(_TestTimeout)"
EnvironmentVariables="DOTNET_ROOT=$(TestDotNetRoot);DOTNET_ROOT_X86=$(TestDotNetRoot)x86"
ContinueOnError="WarnAndContinue">
<Output TaskParameter="ExitCode" PropertyName="_TestErrorCode" />
</Exec>

<!--
Report test status.
-->
<Message Text="Tests succeeded: $(_TestAssembly) [$(_TestEnvironment)]" Condition="'$(_TestErrorCode)' == '0'" Importance="high" />

<PropertyGroup>
<_ResultsFileToDisplay>%(TestToRun.ResultsHtmlPath)</_ResultsFileToDisplay>
<_ResultsFileToDisplay Condition="!Exists('$(_ResultsFileToDisplay)')">%(TestToRun.ResultsStdOutPath)</_ResultsFileToDisplay>
</PropertyGroup>

<!--
Ideally we would set ContinueOnError="ErrorAndContinue" so that when a test fails in multi-targeted test project
we'll still run tests for all target frameworks. ErrorAndContinue doesn't work well on Linux though: https://github.com/Microsoft/msbuild/issues/3961.
-->
<Error Text="Tests failed: $(_ResultsFileToDisplay) [$(_TestEnvironment)]" Condition="'$(_TestErrorCode)' != '0' and '$(_ErrorOnTestFailure)' != 'false'" File="XUnit" />

<ItemGroup>
<FileWrites Include="@(_OutputFiles)"/>
</ItemGroup>
</Target>

</Project>
47 changes: 47 additions & 0 deletions src/Microsoft.DotNet.Arcade.Sdk/tools/XUnitV3/XUnitV3.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. -->
<Project>

<PropertyGroup>
<UseVSTestRunner Condition="'$(UseVSTestRunner)' != 'true'">false</UseVSTestRunner>

<!-- Default to using MTP -->
<UseMicrosoftTestingPlatformRunner Condition="'$(UseMicrosoftTestingPlatformRunner)' == ''">true</UseMicrosoftTestingPlatformRunner>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="xunit.v3" Version="$(XUnitV3Version)" IsImplicitlyDefined="true" PrivateAssets="all" Publish="true" />
<!-- TODO -->
<!-- <PackageReference Include="Microsoft.DotNet.XUnitV3Assert" Version="$(MicrosoftDotNetXUnitAssertVersion)" IsImplicitlyDefined="true" PrivateAssets="all" Publish="true" Condition="'$(UseDotNetXUnitAssert)' == 'true' and '$(TargetFrameworkIdentifier)' == '.NETCoreApp'" /> -->
<PackageReference Include="xunit.runner.visualstudio" Version="$(XUnitRunnerVisualStudioVersion)" IsImplicitlyDefined="true" PrivateAssets="all" Publish="true"/>
</ItemGroup>

<ItemGroup Condition="'$(UseMicrosoftTestingPlatformRunner)' == 'true'">
<PackageReference Include="Microsoft.Testing.Extensions.TrxReport" Version="$(MicrosoftTestingPlatformVersion)" IsImplicitlyDefined="true" PrivateAssets="all" Publish="true" />
<PackageReference Include="Microsoft.Testing.Platform.MSBuild" Version="$(MicrosoftTestingPlatformVersion)" IsImplicitlyDefined="true" PrivateAssets="all" Publish="true" />
<PackageReference Include="Microsoft.Testing.Platform" Version="$(MicrosoftTestingPlatformVersion)" IsImplicitlyDefined="true" PrivateAssets="all" Publish="true" />
</ItemGroup>

<PropertyGroup>
<XUnitDesktopSettingsFile Condition="'$(XUnitDesktopSettingsFile)' == ''">$(MSBuildThisFileDirectory)xunit.runner.json</XUnitDesktopSettingsFile>
<XUnitCoreSettingsFile Condition="'$(XUnitCoreSettingsFile)' == ''">$(MSBuildThisFileDirectory)xunit.runner.json</XUnitCoreSettingsFile>
</PropertyGroup>

<!--
Include settings file (xunit.runner.json) if specified.
-->
<ItemGroup>
<None Include="$(XUnitDesktopSettingsFile)"
CopyToOutputDirectory="PreserveNewest"
Visible="false"
Condition="'$(XUnitDesktopSettingsFile)' != '' and '$(TargetFrameworkIdentifier)' == '.NETFramework'" />

<None Include="$(XUnitCoreSettingsFile)"
CopyToOutputDirectory="PreserveNewest"
Visible="false"
Condition="'$(XUnitCoreSettingsFile)' != '' and '$(TargetFrameworkIdentifier)' == '.NETCoreApp'" />
</ItemGroup>

<Import Project="XUnitV3.Runner.targets" Condition="!$(UseVSTestRunner)"/>
<Import Project="..\VSTest.targets" Condition="$(UseVSTestRunner)"/>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
"shadowCopy": false
}
Loading