mirror of
https://github.com/dotnet/skills.git
synced 2026-09-20 09:49:54 +08:00
Clarify platform detection and MTP hot reload boundaries (#1076)
* Clarify platform and hot reload boundaries Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Address platform and hot reload review feedback Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d3d8e36b-fdc3-470f-81c8-dc8d696590fb * Tighten platform detection response scope Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d3d8e36b-fdc3-470f-81c8-dc8d696590fb * Address follow-up platform review feedback Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d3d8e36b-fdc3-470f-81c8-dc8d696590fb * Improve platform and hot reload eval discrimination Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d3d8e36b-fdc3-470f-81c8-dc8d696590fb * Allow multiline platform causality evidence Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d3d8e36b-fdc3-470f-81c8-dc8d696590fb * Correct dotnet watch restart syntax Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d3d8e36b-fdc3-470f-81c8-dc8d696590fb * Harden xUnit hot reload fixture Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d3d8e36b-fdc3-470f-81c8-dc8d696590fb * Clarify watch project ownership Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d3d8e36b-fdc3-470f-81c8-dc8d696590fb * Expand platform import-order coverage Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d3d8e36b-fdc3-470f-81c8-dc8d696590fb * Complete platform evidence explanations Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d3d8e36b-fdc3-470f-81c8-dc8d696590fb --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d3d8e36b-fdc3-470f-81c8-dc8d696590fb
This commit is contained in:
@@ -1,14 +1,13 @@
|
||||
---
|
||||
name: mtp-hot-reload
|
||||
description: >
|
||||
Set up MTP hot reload for a long-lived edit/re-run loop. Use only for "hot
|
||||
reload tests" or when the user wants a host to keep running and automatically
|
||||
rerun tests after repeated code edits. Covers the package, environment
|
||||
variable, launchSettings.json, dotnet run, and optional filters. For a normal
|
||||
one-time run, including `dotnet test --no-build`, an exact dotnet test
|
||||
command, command/filter errors, TRX/dumps, or merely a failing test, use
|
||||
run-tests. Do not use for writing/debugging test logic, CI, or Visual Studio
|
||||
Test Explorer hot reload.
|
||||
Set up or recover MTP hot reload for a long-lived edit/re-run loop. Use for
|
||||
"hot reload tests", "dotnet run or dotnet test for hot reload", a host that
|
||||
keeps running, unsupported/rude edits, or a watch-based VSTest fallback.
|
||||
Covers setup, run/watch, restarts, filters, and the VSTest no-mutation
|
||||
fallback. Never mutate VSTest for hot reload. For one-time runs, exact
|
||||
commands, filter errors, TRX/dumps, or merely a failing test, use run-tests.
|
||||
Excludes writing/debugging tests, CI, and Test Explorer hot reload.
|
||||
license: MIT
|
||||
---
|
||||
|
||||
@@ -28,7 +27,6 @@ edits and automatically reruns tests.
|
||||
- User needs to write new tests from scratch (use general coding assistance)
|
||||
- User needs to diagnose why a test is failing (use diagnostic skills)
|
||||
- User wants Visual Studio Test Explorer hot reload (different feature, built into VS)
|
||||
- Project uses VSTest -- hot reload requires Microsoft Testing Platform (MTP)
|
||||
- User wants one normal run without rebuilding (use `run-tests`)
|
||||
- User needs CI/CD pipeline configuration
|
||||
|
||||
@@ -39,24 +37,52 @@ edits and automatically reruns tests.
|
||||
| Test project path | No | Path to the test project (.csproj). Defaults to current directory. |
|
||||
| Failing test name or filter | No | Specific test(s) to iterate on |
|
||||
|
||||
## Response sizing
|
||||
|
||||
- If setup is already complete and the user asks only which command to use,
|
||||
return one `dotnet run --project <path>` command and one sentence explaining
|
||||
that it starts the persistent host. Do not repeat package, launch profile, or
|
||||
rude-edit guidance.
|
||||
- If the package is already installed, show only the remaining enable-and-run
|
||||
steps. Do not suggest reinstalling it or add optional persistence/recovery
|
||||
paths unless requested.
|
||||
- For a named test, identify the framework and return one runnable command with
|
||||
that framework's filter syntax. Never substitute MSTest/NUnit `--filter` for
|
||||
xUnit v3 `--filter-method` or TUnit `--treenode-filter`.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Verify the project uses Microsoft Testing Platform
|
||||
### Step 1: Detect the platform before changing anything
|
||||
|
||||
Hot reload requires MTP. It does **not** work with VSTest.
|
||||
|
||||
Follow the detection procedure in the `platform-detection` skill to determine the test platform.
|
||||
Follow the complete evaluated-property procedure in the `platform-detection`
|
||||
skill. Read imported props and package versions as well as the project file.
|
||||
Do this before installing packages, editing files, or returning an MTP launch
|
||||
command.
|
||||
|
||||
**Hard stop for VSTest:** report that MTP hot reload is unavailable for the
|
||||
project as configured, offer migration or Visual Studio Test Explorer as next
|
||||
options, and stop. Do not install the extension, create `launchSettings.json`,
|
||||
set the environment variable, or return a `dotnet run` hot-reload command for
|
||||
that project. Never modify or claim to have modified the project unless the
|
||||
user explicitly asks to migrate it and the change was actually performed.
|
||||
project as configured and stop the MTP setup path. Do not install the extension,
|
||||
create `launchSettings.json`, set the environment variable, change runner
|
||||
properties/packages, or return a `dotnet run` hot-reload command. Never turn a
|
||||
setup request into an implicit VSTest-to-MTP migration.
|
||||
|
||||
Offer one valid non-MTP fallback that preserves the project:
|
||||
|
||||
```shell
|
||||
dotnet watch --project <project-path> test
|
||||
```
|
||||
|
||||
This rebuilds and reruns the existing VSTest project when files change; it is
|
||||
not MTP hot reload. Offer an explicit migration as a separate option, but do not
|
||||
perform it unless the user asks. Exact one-shot test commands remain owned by
|
||||
`run-tests`.
|
||||
|
||||
### Step 2: Add the hot reload NuGet package
|
||||
|
||||
Install the `Microsoft.Testing.Extensions.HotReload` package:
|
||||
First inspect the effective package references. If
|
||||
`Microsoft.Testing.Extensions.HotReload` is already installed, preserve its
|
||||
version and skip this step. Otherwise install it:
|
||||
|
||||
```shell
|
||||
dotnet add <project-path> package Microsoft.Testing.Extensions.HotReload
|
||||
@@ -123,12 +149,41 @@ The test host will start, run the tests, and **remain running** waiting for code
|
||||
|
||||
> **Important**: Hot reload currently works in **console mode only**. There is no support for hot reload in Test Explorer for Visual Studio or Visual Studio Code.
|
||||
|
||||
#### Unsupported edits and rude edits
|
||||
|
||||
Method-signature changes, new types, and other unsupported edits cannot be
|
||||
applied to the active process. Never imply that the stale host picked them up.
|
||||
|
||||
For a directly launched MTP host:
|
||||
|
||||
1. Preserve the exact command, profile, environment, filter, and arguments that
|
||||
started the current host.
|
||||
2. Stop it with `Ctrl+C`.
|
||||
3. Rebuild the same project: `dotnet build <project-path>`.
|
||||
4. Rerun the **same original host command**. Do not replace an unknown existing
|
||||
invocation with a generic `dotnet run` command.
|
||||
|
||||
If repeated unsupported edits are expected, offer a watch-managed restart
|
||||
fallback:
|
||||
|
||||
```shell
|
||||
# PowerShell
|
||||
$env:TESTINGPLATFORM_HOTRELOAD_ENABLED = "1"
|
||||
$env:DOTNET_WATCH_RESTART_ON_RUDE_EDIT = "1"
|
||||
dotnet watch --project <project-path> run -- <existing-MTP-arguments>
|
||||
```
|
||||
|
||||
`dotnet watch` restarts the process when a rude edit cannot be applied. Without
|
||||
the auto-restart variable, accept the restart prompt or press `Ctrl+R`. Preserve
|
||||
any existing test filter after `--`.
|
||||
|
||||
### Step 6: Finalize
|
||||
|
||||
Once all tests pass:
|
||||
|
||||
1. Stop the test host (Ctrl+C)
|
||||
2. Run a full `dotnet test` to confirm all tests pass with a clean build
|
||||
2. Use `run-tests` when the user requests an exact one-shot validation command,
|
||||
flags, filter, TRX, or dump
|
||||
3. Optionally remove `TESTINGPLATFORM_HOTRELOAD_ENABLED` from the environment or keep `launchSettings.json` for future use
|
||||
|
||||
## Validation
|
||||
@@ -144,7 +199,7 @@ Once all tests pass:
|
||||
| Pitfall | Solution |
|
||||
|---------|----------|
|
||||
| Using `dotnet test` instead of `dotnet run` | Hot reload requires `dotnet run --project <path>` to run the test host directly in console mode |
|
||||
| Project uses VSTest, not MTP | Hot reload requires MTP. Migrate to MTP first or use VS Test Explorer hot reload |
|
||||
| Project uses VSTest, not MTP | Do not mutate it. Offer `dotnet watch --project <path> test` as a rebuild/rerun fallback or a separate explicit migration |
|
||||
| Forgetting to set the environment variable | Set `TESTINGPLATFORM_HOTRELOAD_ENABLED=1` before running |
|
||||
| Expecting Test Explorer integration | Console mode only -- no VS/VS Code Test Explorer support |
|
||||
| Making unsupported code changes (rude edits) | Some changes (adding new types, changing method signatures) require a restart. Stop and re-run |
|
||||
| Making unsupported code changes (rude edits) | Stop, rebuild, and rerun the same host invocation, or use `dotnet watch` with restart-on-rude-edit behavior |
|
||||
|
||||
@@ -22,15 +22,32 @@ Determine **which test platform** (VSTest or Microsoft.Testing.Platform) and **w
|
||||
Honor the user's requested labels and order exactly, substituting the actual
|
||||
classification for every placeholder. Start with the verdict: never put a
|
||||
heading, scratch analysis, tool syntax, or an echoed template before it. Follow
|
||||
with one concise evidence line naming only the repository facts that decide the
|
||||
result.
|
||||
with one concise evidence sentence naming the repository facts needed to justify
|
||||
every requested classification. When `Framework` is requested, name the package
|
||||
or project SDK that identifies it. Use a second sentence only for a conflict, an
|
||||
incomplete configuration, or target-framework-specific differences.
|
||||
|
||||
`Platform` means the platform that actually executes tests: **VSTest** or
|
||||
**MTP**. If conflicting or incomplete configuration prevents execution, report
|
||||
it as unavailable rather than inventing a successful platform. Include command
|
||||
mode only when the user asks for it. When the user asks which single signal
|
||||
decides the result, name that signal first and keep bridge or output
|
||||
prerequisites subordinate rather than presenting every property as co-equal.
|
||||
it as unavailable rather than inventing a successful platform.
|
||||
|
||||
Apply this scope gate before drafting the evidence:
|
||||
|
||||
| User asks for | Evidence to include | Omit |
|
||||
|---------------|---------------------|------|
|
||||
| Platform and framework | Final runner selector and its winning source; package or project SDK identifying the framework; when needed, the property that makes it executable | Command mode; common SDK facts; `OutputType` unless it is missing or conflicting |
|
||||
| The single deciding signal | That runner-selection property, why its source wins, and why a competing package does not select or imply VSTest; still name the package or project SDK identifying a requested framework | Bridge, `OutputType`, SDK mode, and unrelated prerequisites when the configuration is complete |
|
||||
| Platforms per target framework | Only the conditional final values that differ by target | Common properties and project-wide SDK commentary |
|
||||
| Explicit opt-out | Final `UseVSTest` value and its winning source | Superseded defaults unless they create a conflict |
|
||||
| `dotnet test` mode | The separate command-mode and executed-platform classifications | None of the requested axes |
|
||||
|
||||
If the requested labels omit `dotnet test mode`, do not state or explain command
|
||||
mode anywhere in the response. An exact bridge property may still be decisive
|
||||
platform evidence, but do not turn it into SDK or CLI-mode commentary.
|
||||
|
||||
When import precedence decides a property, state why the winning source wins
|
||||
(for example, it is imported later or its condition applies), not merely that it
|
||||
contains the final value or overrides another assignment.
|
||||
|
||||
When a classic-project request also asks for the command family, add a direct
|
||||
line such as `Command family: MSBuild + vstest.console.exe`; do not turn it into
|
||||
@@ -38,11 +55,27 @@ an optional alternative or add an unnecessary build qualifier.
|
||||
|
||||
For a file-backed request, enumerate the following configuration names once,
|
||||
then read every relevant file that is present in one batched operation:
|
||||
`global.json`, `.csproj`, `packages.config`, `Directory.Build.props`, and
|
||||
`Directory.Packages.props`. A setting absent from the project file may be
|
||||
defined by imported repository files, so never infer its final value from the
|
||||
`.csproj` alone. Do not search the web or inspect unrelated files when
|
||||
repository configuration is sufficient.
|
||||
`global.json`, `.csproj`, `packages.config`, `Directory.Build.props`,
|
||||
`Directory.Build.targets`, `Directory.Packages.props`, and explicit imported
|
||||
`.props` / `.targets`. A setting absent from the project file may be defined by
|
||||
an import, so never infer its final value from the `.csproj` alone. Do not search
|
||||
the web or inspect unrelated files when repository configuration is sufficient.
|
||||
|
||||
Resolve properties in the actual MSBuild import order, not with a fixed
|
||||
"project beats props" rule. For every applicable target framework:
|
||||
|
||||
1. Follow the import graph and conditions. A later applicable assignment wins.
|
||||
`Directory.Build.props` is normally imported before the project body, so an
|
||||
unconditional project assignment normally overrides it; later `.targets`
|
||||
can override the project again.
|
||||
2. Record the final value and its winning source for `UseVSTest`, the framework
|
||||
runner selector, `TestingPlatformDotnetTestSupport`, and `OutputType`.
|
||||
3. Treat `Directory.Packages.props` as version evidence unless it also contains
|
||||
relevant properties. Resolve package/SDK versions before applying
|
||||
version-dependent defaults.
|
||||
4. Never infer a property from package presence. A package or SDK default counts
|
||||
only when that resolved version actually supplies it and no later assignment
|
||||
overrides it.
|
||||
|
||||
## Detecting the project system
|
||||
|
||||
@@ -79,32 +112,47 @@ with `HintPath` values. Use both sources.
|
||||
|
||||
If the user explicitly requests `dotnet test` mode, read
|
||||
[`references/command-mode.md`](references/command-mode.md) before answering.
|
||||
Do not load that reference for a platform/framework-only request.
|
||||
Do not load that reference or mention command mode for a
|
||||
platform/framework-only request.
|
||||
|
||||
On SDK 8/9, `dotnet test` command mode is always VSTest, although a complete
|
||||
bridge can still execute tests on MTP. Only SDK 10+ `global.json` can select
|
||||
native MTP command mode. Never collapse command mode and executed platform into
|
||||
one classification.
|
||||
For an SDK 8/9 request that explicitly asks about command mode and has no
|
||||
effective bridge, state all three facts in one causal sentence: the runner makes
|
||||
the project MTP-capable, `dotnet test` remains in VSTest mode, and the missing
|
||||
bridge means VSTest actually executes the tests. Mention that native MTP command
|
||||
mode starts with SDK 10 only when it helps explain that result.
|
||||
|
||||
When execution is permitted and neither the prompt nor `global.json` identifies
|
||||
the SDK, run `dotnet --version` once. For read-only identification requests that
|
||||
prohibit execution, do not probe the installed SDK; use repository facts and
|
||||
state any necessary SDK assumption.
|
||||
|
||||
Evaluate final property values in this order:
|
||||
After resolving final property values, classify in this order:
|
||||
|
||||
1. Explicit `UseVSTest=true` selects VSTest. If `global.json` simultaneously
|
||||
selects the native MTP runner, report `Platform: unavailable` because the
|
||||
repository and project conflict.
|
||||
1. Final `UseVSTest=true` selects VSTest. If `global.json` simultaneously
|
||||
selects native MTP command mode, report `Platform: unavailable` because the
|
||||
command mode and project opt-out conflict.
|
||||
2. A native-MTP selection in `global.json` executes a compatible MTP
|
||||
application with final `OutputType=Exe` on MTP. A VSTest-only, library-output,
|
||||
or opted-out project is unavailable, not a successful MTP execution.
|
||||
3. Otherwise, an enabled MTP runner plus
|
||||
application with final `OutputType=Exe` on MTP. A VSTest-only,
|
||||
library-output, or opted-out project is unavailable.
|
||||
3. On SDK 8/9, an enabled MTP runner plus final
|
||||
`TestingPlatformDotnetTestSupport=true` plus final `OutputType=Exe` executes
|
||||
on MTP.
|
||||
4. A runner and bridge with non-executable output is incomplete and unavailable.
|
||||
Without the complete runner/bridge/executable combination, a dual-capable
|
||||
MSTest or NUnit project executes on VSTest.
|
||||
4. If the runner is enabled but the bridge is absent or false, a dual-capable
|
||||
MSTest, NUnit, or xUnit project remains on VSTest: the runner establishes MTP
|
||||
capability, but SDK 8/9 `dotnet test` cannot reach it and the VSTest adapter
|
||||
executes the tests instead. If the bridge is true but no runner is enabled,
|
||||
the project also remains on VSTest.
|
||||
5. A runner and bridge with non-executable output is incomplete and unavailable.
|
||||
An MTP-only framework that cannot be reached by the selected SDK path is also
|
||||
unavailable, not VSTest.
|
||||
|
||||
Keep each signal's role exact:
|
||||
|
||||
- The runner property selects the test application.
|
||||
- `TestingPlatformDotnetTestSupport=true` lets SDK 8/9 `dotnet test` reach that
|
||||
application.
|
||||
- `OutputType=Exe` supplies the executable host shape. It does **not** select or
|
||||
enable MTP.
|
||||
|
||||
Do not confuse the `MSTest` metapackage with the `MSTest.Sdk` project SDK.
|
||||
`PackageReference Include="MSTest"` plus `EnableMSTestRunner=true` enables the
|
||||
@@ -112,9 +160,10 @@ MSTest MTP runner, but it does **not** implicitly set
|
||||
`TestingPlatformDotnetTestSupport`.
|
||||
|
||||
MSTest.Sdk enables the MTP runner by default. Check its resolved version and
|
||||
evaluated properties for bridge behavior: versions such as 3.8 also set
|
||||
`TestingPlatformDotnetTestSupport`, while newer SDKs on .NET 10 may expect native
|
||||
MTP mode instead. `<UseVSTest>true</UseVSTest>` opts back into VSTest.
|
||||
evaluated properties for bridge behavior: version 3.8 supplies
|
||||
`TestingPlatformDotnetTestSupport` unless a later assignment overrides it,
|
||||
while newer SDKs on .NET 10 may expect native MTP mode instead.
|
||||
`<UseVSTest>true</UseVSTest>` opts back into VSTest.
|
||||
|
||||
| Signal | Meaning |
|
||||
|--------|---------|
|
||||
@@ -129,11 +178,22 @@ MTP mode instead. `<UseVSTest>true</UseVSTest>` opts back into VSTest.
|
||||
|
||||
`Microsoft.NET.Test.Sdk` alone is not decisive; it can remain for compatibility
|
||||
in an MTP-enabled project. When an explicit override decides the result, name
|
||||
the override only; do not summarize the defaults it supersedes.
|
||||
When a runner-selection property competes with `Microsoft.NET.Test.Sdk`, name
|
||||
the runner property as decisive and the package as non-decisive compatibility
|
||||
support; omit unrelated execution prerequisites unless they are needed to show
|
||||
that the selected runner can actually execute.
|
||||
the final override and its source, not the superseded default.
|
||||
When a runner-selection property competes with `Microsoft.NET.Test.Sdk`, say
|
||||
that the runner property selects MTP and `Microsoft.NET.Test.Sdk` does **not**
|
||||
select or imply VSTest. It may remain as compatibility support, but that is
|
||||
secondary. For a request asking which single signal decides, stop there; do not
|
||||
enumerate bridge or host-shape prerequisites when the configuration is complete.
|
||||
|
||||
Use causal evidence, not a bag of signals. For example:
|
||||
|
||||
```text
|
||||
Platform: MTP
|
||||
Framework: NUnit
|
||||
|
||||
Directory.Build.props supplies final EnableNUnitRunner=true and
|
||||
TestingPlatformDotnetTestSupport=true, so NUnit executes on MTP.
|
||||
```
|
||||
|
||||
For an incompatible configuration, give one minimal alignment choice after the
|
||||
verdict without modifying files: either select the project's configured
|
||||
|
||||
Reference in New Issue
Block a user