diff --git a/dotnet/Templates/Microsoft.MacCatalyst.Templates/maccatalysttest/csharp/Main.cs b/dotnet/Templates/Microsoft.MacCatalyst.Templates/maccatalysttest/csharp/Main.cs index c66e487fc13f..4ea38ded034b 100644 --- a/dotnet/Templates/Microsoft.MacCatalyst.Templates/maccatalysttest/csharp/Main.cs +++ b/dotnet/Templates/Microsoft.MacCatalyst.Templates/maccatalysttest/csharp/Main.cs @@ -63,7 +63,13 @@ public void WillConnect (UIScene scene, UISceneSession session, UISceneConnectio var documentsPath = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments); var resultsPath = Path.Combine (documentsPath, "TestResults"); + // Forward args from 'dotnet test', which sends the MTP protocol config + // (--server / --dotnet-test-pipe) via the command line. + // Environment.GetCommandLineArgs()[0] is the executable path, not an argument. + string [] cliArgs = Environment.GetCommandLineArgs (); + string [] mtpArgs = cliArgs.Length > 1 ? cliArgs [1..] : []; var builder = await TestApplication.CreateBuilderAsync ([ + .. mtpArgs, "--results-directory", resultsPath, "--report-trx" ]); diff --git a/dotnet/Templates/Microsoft.macOS.Templates/macostest/csharp/Main.cs b/dotnet/Templates/Microsoft.macOS.Templates/macostest/csharp/Main.cs index 3c3c16808d33..d829f575772e 100644 --- a/dotnet/Templates/Microsoft.macOS.Templates/macostest/csharp/Main.cs +++ b/dotnet/Templates/Microsoft.macOS.Templates/macostest/csharp/Main.cs @@ -52,7 +52,13 @@ public override void DidFinishLaunching (NSNotification notification) var documentsPath = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments); var resultsPath = Path.Combine (documentsPath, "TestResults"); + // Forward args from 'dotnet test', which sends the MTP protocol config + // (--server / --dotnet-test-pipe) via the command line. + // Environment.GetCommandLineArgs()[0] is the executable path, not an argument. + string [] cliArgs = Environment.GetCommandLineArgs (); + string [] mtpArgs = cliArgs.Length > 1 ? cliArgs [1..] : []; var builder = await TestApplication.CreateBuilderAsync ([ + .. mtpArgs, "--results-directory", resultsPath, "--report-trx" ]); diff --git a/dotnet/targets/Xamarin.Shared.Sdk.MSTest.props b/dotnet/targets/Xamarin.Shared.Sdk.MSTest.props index 83ced6200365..63f64f433235 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.MSTest.props +++ b/dotnet/targets/Xamarin.Shared.Sdk.MSTest.props @@ -11,6 +11,14 @@ false true + + false diff --git a/tests/dotnet/UnitTests/DotNetTestTest.cs b/tests/dotnet/UnitTests/DotNetTestTest.cs index fed4f817a74b..5b1faf96e471 100644 --- a/tests/dotnet/UnitTests/DotNetTestTest.cs +++ b/tests/dotnet/UnitTests/DotNetTestTest.cs @@ -13,10 +13,8 @@ public class DotNetTestTest : TestBaseClass { [Test] [TestCase (ApplePlatform.iOS, "iostest")] [TestCase (ApplePlatform.TVOS, "tvostest")] - // macOS and Mac Catalyst don't use mlaunch (they use 'open' via Desktop.targets), - // so MTP support requires a different approach for these platforms. - // [TestCase (ApplePlatform.MacCatalyst, "maccatalysttest")] - // [TestCase (ApplePlatform.MacOSX, "macostest")] + [TestCase (ApplePlatform.MacCatalyst, "maccatalysttest")] + [TestCase (ApplePlatform.MacOSX, "macostest")] public void DotNetTest (ApplePlatform platform, string template) { Configuration.IgnoreIfIgnoredPlatform (platform); @@ -26,24 +24,21 @@ public void DotNetTest (ApplePlatform platform, string template) DotNet.AssertNew (outputDir, template); var proj = Path.Combine (outputDir, $"{template}.csproj"); - // Boot a simulator so that ComputeRunArguments can find a device + var isDesktop = platform == ApplePlatform.MacOSX || platform == ApplePlatform.MacCatalyst; var log = ConsoleLogger.Instance; var simService = new SimulatorService (log); - var runtimeService = new RuntimeService (log); - var device = GetOrCreateDevice (platform, simService, runtimeService); + SimulatorDeviceInfo? device = null; - if (!device.IsBooted) - Assert.That (simService.Boot (device.Udid), Is.True, $"Failed to boot simulator {device.Udid}."); + if (!isDesktop) { + // Boot a simulator so that ComputeRunArguments can find a device + var runtimeService = new RuntimeService (log); + device = GetOrCreateDevice (platform, simService, runtimeService); - try { - // dotnet test internally calls ComputeRunArguments via MSBuild API without - // forwarding /p: properties, so we must set them in the project file directly. - var csproj = File.ReadAllText (proj); - csproj = csproj.Replace ( - "", - $" true\n {device.Udid}\n "); - File.WriteAllText (proj, csproj); + if (!device.IsBooted) + Assert.That (simService.Boot (device.Udid), Is.True, $"Failed to boot simulator {device.Udid}."); + } + try { // Replace generated tests with a single passing test var testFile = Path.Combine (outputDir, "Test1.cs"); File.WriteAllText (testFile, $@"namespace {template}; @@ -59,21 +54,26 @@ public void TestMethod1 () // Run 'dotnet test' directly using Execution.RunAsync. // dotnet test's MTP flow doesn't forward /p: properties to its internal - // ComputeRunArguments MSBuild API call, so properties must be in the csproj. + // ComputeRunArguments MSBuild API call, so pass properties as environment + // variables instead — MSBuild picks those up as global properties in the + // child process. var env = new Dictionary (); env ["MSBuildSDKsPath"] = null; env ["MSBUILD_EXE_PATH"] = null; + env ["UseFloatingTargetPlatformVersion"] = "true"; + if (device is not null) + env ["Device"] = device.Udid; var binlog = Path.Combine (outputDir, "log-test.binlog"); var testArgs = new List { "test", proj, - $"--device:{device.Udid}", $"/bl:{binlog}" }; var testResult = Execution.RunAsync (DotNet.Executable, testArgs, env, Console.Out, workingDirectory: outputDir, timeout: TimeSpan.FromMinutes (10)).Result; Assert.That (testResult.ExitCode, Is.EqualTo (0), $"'dotnet test' failed with exit code {testResult.ExitCode}.\nBinlog: {binlog}\nOutput:\n{testResult.Output.MergedOutput}"); } finally { - simService.Shutdown (device.Udid); + if (device is not null) + simService.Shutdown (device.Udid); } }