Add dotnet test --list-devices support for MAUI - #54565
Conversation
There was a problem hiding this comment.
Pull request overview
This PR extends the dotnet test Microsoft Testing Platform (MTP) command to support --list-devices, mirroring the existing dotnet run --list-devices behavior so MAUI/Android/iOS test projects can enumerate device IDs without building or running tests.
Changes:
- Added
dotnet test --list-devicesoption and an early-exit listing flow that callsComputeAvailableDevicesviaRunCommandSelector. - Updated
RunCommandSelector.TrySelectDeviceto accept acommandNameso the printed example uses the invoking command (dotnet runvsdotnet test). - Added integration tests for listing behavior and updated the MTP help snapshot.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/dotnet.Tests/CommandTests/Test/snapshots/MTPHelpSnapshotTests.VerifyMTPHelpOutput.verified.txt | Updates dotnet test MTP help snapshot to include --list-devices. |
| test/dotnet.Tests/CommandTests/Test/GivenDotnetTestSelectsDevice.cs | Adds integration tests covering --list-devices scenarios (multi-TFM, single device, missing target, solution error). |
| src/Cli/Microsoft.DotNet.Cli.Definitions/Commands/Test/TestCommandDefinition.MicrosoftTestingPlatform.cs | Adds the --list-devices option to the MTP dotnet test command definition. |
| src/Cli/dotnet/Commands/Test/MTP/SolutionAndProjectUtility.cs | Passes commandName: "dotnet test" into device selection to render correct examples. |
| src/Cli/dotnet/Commands/Test/MTP/Options.cs | Extends BuildOptions to carry the ListDevices flag. |
| src/Cli/dotnet/Commands/Test/MTP/MSBuildUtility.cs | Wires --list-devices parse result into BuildOptions. |
| src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformTestCommand.cs | Implements the --list-devices early-exit flow and improves solution handling for --device. |
| src/Cli/dotnet/Commands/Run/RunCommandSelector.cs | Adds commandName parameter to TrySelectDevice and uses it in example output. |
| src/Cli/dotnet/Commands/Run/RunCommand.cs | Updates dotnet run to pass commandName: "dotnet run" into TrySelectDevice. |
42c6c89 to
838816d
Compare
838816d to
ea200a3
Compare
Reviewed the diff against 🐛 Bugs / Correctness1.
|
ea200a3 to
baf0f8f
Compare
|
Thanks for the thorough review! Pushed a follow-up commit (squashed into the single commit on the branch). Summary of what I addressed: Adopted:
Skipped (with rationale):
|
21f746b to
34938ee
Compare
Evangelink
left a comment
There was a problem hiding this comment.
Note
This review was generated with AI assistance and reviewed before posting.
Overall this is a clean change that mirrors dotnet run --list-devices closely — signatures and call sites are consistent, the new resource strings exist, .xlf files are regenerated correctly, and the help snapshot matches. A few items below, mostly around test coverage and a behavioral inconsistency between the --device and --list-devices solution guards.
|
|
||
| // Step 2: List devices. This calls ComputeAvailableDevices if the target exists; | ||
| // otherwise it silently no-ops (matches `dotnet run --list-devices`). | ||
| if (!selector.TrySelectDevice( |
There was a problem hiding this comment.
Low confidence / pre-existing: TryComputeAvailableDevices (in RunCommandSelector) returns false identically for three distinct cases — target absent, restore failed, and ComputeAvailableDevices build failed — and TrySelectDevice treats a false target result as "no device support" and returns true. So dotnet test --list-devices on a project that has the target but fails to restore/build exits 0 with no output rather than surfacing the failure. This is inherited from the dotnet run selector, but the behavior is now also on the test path — flagging as an opportunity rather than a blocker.
There was a problem hiding this comment.
Agree this is worth documenting, but keeping the current behavior intentionally: it matches dotnet run --list-devices exactly (the whole point of using RunCommandSelector here is parity with the run path). Improving the diagnostics on restore/build failure would be a good separate change in RunCommandSelector itself, benefiting both dotnet run and dotnet test users.
7524011 to
5b167f7
Compare
Evangelink
left a comment
There was a problem hiding this comment.
Note
This review was generated with AI assistance and reviewed before posting.
Re-reviewed after the latest push. The two earlier findings look correctly addressed: the --device + --solution guard was moved out of the TargetFramework check so it now rejects unconditionally (matching --list-devices), and ItErrorsWhenUsingDeviceForSolution covers both the -f and no--f cases. One new blocking issue from the merge with main below.
| string.Format(CliCommandStrings.RunCommandExceptionUnableToRunSpecifyDevice, "--device")); | ||
| } | ||
|
|
||
| [Fact] |
There was a problem hiding this comment.
Blocking (compile break): the merge from main migrated this file to MSTest.Sdk — the pre-existing tests above (lines ~18-196) are now [TestClass]/[TestMethod]/[DataRow], but every PR-added test from here down (lines 198-379) still uses xUnit [Fact]/[Theory]/[InlineData]. dotnet.Tests.csproj references Microsoft.NET.TestFramework.MSTest.csproj and has no using Xunit (the Xunit global using only lives in the non-MSTest Microsoft.NET.TestFramework.csproj), so these attributes won't resolve — this is now the only file in dotnet.Tests containing [Fact]. Note the Finding-1 fix ItErrorsWhenUsingDeviceForSolution also uses [Theory]/[InlineData], so it won't compile either. Convert all PR-added tests: [Fact] -> [TestMethod], [Theory] -> [TestMethod], [InlineData(x)] -> [DataRow(x)]. The tests use FluentAssertions and no Assert.Throws, so the attributes are the only change needed.
There was a problem hiding this comment.
Done in 1763335 — converted every PR-added test in this file to MSTest: [Fact] -> [TestMethod], [Theory] + [InlineData(x)] -> [TestMethod] + [DataRow(x)], added [TestClass] on the class, dropped the ITestOutputHelper ctor injection in favor of the parameterless ctor + inherited Log property (matches the pattern the rest of dotnet.Tests uses post-migration). Assertions and test logic are unchanged. Verified dotnet build test/dotnet.Tests/dotnet.Tests.csproj compiles clean locally.
Implements the spec from documentation/general/dotnet-run-for-maui.md to add `--list-devices` and `--device` support to `dotnet test` for MTP-enabled projects. Shares the `RunCommandSelector` plumbing with `dotnet run` so target-framework prompting, MSBuild evaluation, and device discovery all behave consistently between the two commands. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…t-test-list-devices # Conflicts: # test/dotnet.Tests/CommandTests/Test/GivenDotnetTestSelectsDevice.cs
5b167f7 to
1763335
Compare
Evangelink
left a comment
There was a problem hiding this comment.
Note
This review was generated with AI assistance and reviewed before posting.
Re-reviewed the latest push. The blocking compile break is fully resolved — all PR-added tests now use MSTest attributes ([TestMethod]/[DataRow]), and there are no remaining [Fact]/[Theory]/[InlineData] or other xUnit references anywhere in dotnet.Tests. Combined with the earlier rounds, everything I raised is addressed:
--device+--solutionis now rejected unconditionally (parity with--list-devices+--solution), covered by the parameterizedItErrorsWhenUsingDeviceForSolution.- The
--device-on-solution error-message fix has regression coverage. - The restore/build-failure silent-success behavior is intentional parity with
dotnet run --list-devices, reasonably deferred to a separate change inRunCommandSelector.
The --list-devices flow mirrors dotnet run --list-devices cleanly, signatures/call sites are consistent, resource strings and .xlf regeneration are correct, and the help snapshot matches. LGTM.
Expands on #54295 (which added
dotnet test --device) to implement the--list-devicesswitch ondotnet test, as described indotnet-run-for-maui.md. This lets users discover the device identifiers they can pass to--devicefor MAUI/Android/iOS test projects without first having to run a build.Behavior
dotnet test --list-devicesmirrorsdotnet run --list-devices:$(TargetFramework)for multi-targeted projects in interactive mode; errors with a--frameworksuggestion in non-interactive mode.ComputeAvailableDevicesMSBuild target viaRunCommandSelectorand prints the available devices with a friendlydotnet test --device <id>example.ComputeAvailableDevicestarget, exits silently with success (matchesdotnet run --list-devices).Implementation notes
To keep the listing flow structurally identical to
dotnet run --list-devices,HandleListDevicesreuses a singleRunCommandSelectorinstance forTrySelectTargetFramework->InvalidateGlobalProperties->TrySelectDevice(listDevices: true), the same sequence asRunCommand.TrySelectTargetFrameworkAndDeviceIfNeeded.RunCommandSelector.TrySelectDevicegained a requiredcommandNameparameter so the listed/error example rendersdotnet test --device <id>instead of the previously hard-codeddotnet run --device <id>. The two existing call sites (dotnet run, per-TFM device selection in tests) pass"dotnet run"and"dotnet test"respectively.Code review surfaced a separate latent bug from #54295: when
--devicewas used against a solution, the error told users to specify--frameworkeven though that wouldn't fix the failure. Both--deviceand--list-devicesnow throwTestCommandUseProject(Specifying a project for 'dotnet test' should be via '--project'.). The--deviceguard applies unconditionally, including when-f/--frameworkis also passed, matching--list-devicesbehavior.Tests
Six new integration tests in
GivenDotnetTestSelectsDevice:-f-fComputeAvailableDevices--projecthint when--list-devicesis run against a solution--projecthint when--deviceis used against a solution (parameterized with and without-f)The MTP help snapshot is also updated for the new
--list-devicesline.Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com