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);
}
}