Minimax DOCX
poco-ai/poco-claw
Professional DOCX document creation, editing, and formatting using OpenXML SDK (.NET).
Use this skill before answering, planning, or editing any MSTest 3.x-to-4.x upgrade or post-upgrade failure.
$ npx skills add dotnet/skills --skill migrate-mstest-v3-to-v4 -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install dotnet/skills migrate-mstest-v3-to-v4 --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/dotnet/skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 .claude/skills/migrate-mstest-v3-to-v4 && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "migrate-mstest-v3-to-v4" agent skill from https://github.com/dotnet/skills/tree/main/plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 into .claude/skills/migrate-mstest-v3-to-v4/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "migrate-mstest-v3-to-v4", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/dotnet/skills/tree/main/plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4Type this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add dotnet/skills --skill migrate-mstest-v3-to-v4 -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install dotnet/skills migrate-mstest-v3-to-v4 --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dotnet/skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 .agents/skills/migrate-mstest-v3-to-v4 && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "migrate-mstest-v3-to-v4" agent skill from https://github.com/dotnet/skills/tree/main/plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 into .agents/skills/migrate-mstest-v3-to-v4/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "migrate-mstest-v3-to-v4", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add dotnet/skills --skill migrate-mstest-v3-to-v4 -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install dotnet/skills migrate-mstest-v3-to-v4 --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dotnet/skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 .cursor/skills/migrate-mstest-v3-to-v4 && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "migrate-mstest-v3-to-v4" agent skill from https://github.com/dotnet/skills/tree/main/plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 into .cursor/skills/migrate-mstest-v3-to-v4/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "migrate-mstest-v3-to-v4", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/dotnet/skills.git --path plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add dotnet/skills --skill migrate-mstest-v3-to-v4 -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install dotnet/skills migrate-mstest-v3-to-v4 --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dotnet/skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 .gemini/skills/migrate-mstest-v3-to-v4 && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "migrate-mstest-v3-to-v4" agent skill from https://github.com/dotnet/skills/tree/main/plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 into .gemini/skills/migrate-mstest-v3-to-v4/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "migrate-mstest-v3-to-v4", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install dotnet/skills migrate-mstest-v3-to-v4Installs for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add dotnet/skills --skill migrate-mstest-v3-to-v4 -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/dotnet/skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 .github/skills/migrate-mstest-v3-to-v4 && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "migrate-mstest-v3-to-v4" agent skill from https://github.com/dotnet/skills/tree/main/plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 into .github/skills/migrate-mstest-v3-to-v4/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "migrate-mstest-v3-to-v4", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add dotnet/skills --skill migrate-mstest-v3-to-v4 -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install dotnet/skills migrate-mstest-v3-to-v4 --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dotnet/skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 .opencode/skills/migrate-mstest-v3-to-v4 && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "migrate-mstest-v3-to-v4" agent skill from https://github.com/dotnet/skills/tree/main/plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 into .opencode/skills/migrate-mstest-v3-to-v4/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "migrate-mstest-v3-to-v4", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
migrate-mstest-v3-to-v4Use this skill before answering, planning, or editing any MSTest 3.x-to-4.x upgrade or post-upgrade failure.
Migrate Mstest V3 To V4 is an agent skill from dotnet/skills, published by the product's own GitHub organization. Use this skill before answering, planning, or editing any MSTest 3.x-to-4.x upgrade or post-upgrade failure. Triggers include "MSTest v4 breaking changes"; CS0507/CS0103/CS1061/CS1615; ExecuteAsync, CallerInfo, DisplayName, or custom TestMethodAttribute; ClassCleanupBehavior; ContainsKey; ThrowsExactly or ExpectedException; IsInstanceOfType out parameters; TestTimeout.Infinite; ManagedType; net6/net7 compatibility; TestCase.Id history; TestName in ClassInitialize; TreatDiscoveryWarningsAsErrors; discovery errors…
Its SKILL.md is about 7.2k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It works with .NET. The repository describes itself as: Repository for skills to assist AI coding agents with .NET and C. The licence is MIT.
5 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 1d40f95. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
dotnetFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Migrate Mstest V3 To V4 loads about 7.2k tokens when it runs. Until then it costs about 182 tokens; SKILL.md has 3,008 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from dotnet/skills at commit 1d40f95, republished under its MIT licence (© dotnet). 3,008 words, ~7,217 tokens.
.claude/skills/migrate-mstest-v3-to-v4/SKILL.md (or your agent's skills folder).Migrate a test project from MSTest v3 to MSTest v4. The outcome is a project using MSTest v4 that builds cleanly, passes tests, and accounts for every source-incompatible and behavioral change. MSTest v4 is not binary compatible with MSTest v3 -- any library compiled against v3 must be recompiled against v4.
Inspect the supplied project and source before searching the web or answering
from memory. Classify the request as a focused source fix, runtime behavior
change, CI discovery issue, compatibility question, or full migration, then
follow the matching row below. A clean compile does not exclude this skill:
discovery failures, TestContext lifecycle exceptions, and test-history
changes are runtime migration failures.
MSTest.TestFramework, MSTest.TestAdapter, or MSTest metapackage from 3.x to 4.xMSTest.Sdk from 3.x to 4.xTestMethodAttribute or ConditionBaseAttribute implementations for v4migrate-mstest-v1v2-to-v3 first, then return here| Input | Required | Description |
|---|---|---|
| Project or solution path | No | The .csproj, .sln, or .slnx entry point containing MSTest test projects. Discover it yourself by globbing the working directory; ask only when nothing is found or the choice is genuinely ambiguous |
| Build command | No | How to build (e.g., dotnet build, a repo build script). Auto-detect if not provided |
| Test command | No | How to run tests (e.g., dotnet test). Auto-detect if not provided |
| Detected request or state | Required action |
|---|---|
| Files are supplied in the current workspace | Search there and open the literal returned paths. The skill directory is not the project directory. If one tool rejects a valid path, retry with another available reader/editor; do not ask the user for a path you can discover. |
| User asks to apply changes to supplied files: "fix my project/files", "please update this source", "make the changes", or "then build and run" | Edit every affected occurrence. Run the narrowest meaningful build/test command against the actual package version; skill activation is not a reason to stop at advice. |
| User asks "what should I expect?", "how do I fix these changes?", for compatibility advice, or for a plan | Answer directly from the actual project state even when source is visible. Keep a single-symptom answer focused; include only adjacent risks that change the decision. |
| Unsupported TFM in a full migration | Update the TFM first, then update MSTest packages, then fix source breaks. Do not bury this order in a release-note inventory. |
Custom TestMethodAttribute subclass | Treat ExecuteAsync, CallerInfo propagation, display-name handling, and the subclass's retry/result semantics as one coupled migration. Fix the actual class, not a placeholder example. |
MSTest.Sdk v4 source/API errors (ManagedType, TestTimeout, Contains) | Give the exact source replacements, then add the adjacent runner warning: MTP mode no longer supplies Microsoft.NET.Test.Sdk; add it only if VSTest discovery is still required. |
MSTest.Sdk v4 plus vstest.console | This is a v4 change: MTP mode no longer brings Microsoft.NET.Test.Sdk. Keep MTP and add that package for transitional VSTest discovery, opt into UseVSTest, or migrate CI to dotnet test; state which runner the choice preserves. |
TestMethodAttribute subclasses, show the full fixed class including CallerInfo propagation to the base constructor. Mention any related analyzer that could have caught this earlier (e.g., MSTEST0006 for ExpectedException). When the project uses MSTest.Sdk, also state that v4 MTP mode no longer supplies Microsoft.NET.Test.Sdk and whether that affects the visible runner. Do not walk through the entire migration workflow.UseVSTest to switch the project runner, or switch CI to MTP-native dotnet test. Do not walk through the full migration workflow.Commit strategy: Do not create commits unless the user asks. Keep package, source, and behavioral changes logically separable in the diff, but finish and verify the requested migration.
MSTest, MSTest.TestFramework, MSTest.TestAdapter, or MSTest.Sdk in .csproj, Directory.Build.props, or Directory.Packages.props.migrate-mstest-v1v2-to-v3 first.TestMethodAttribute subclasses -- these require changes in v4.ExpectedExceptionAttribute -- removed in v4 (deprecated since v3 with analyzer MSTEST0006).Assert.ThrowsException (deprecated) -- removed in v4.First resolve the latest stable v4 version from the configured package source. Pin that exact
version consistently in the metapackage, individual packages, MSTest.Sdk, and central package
management.
MSTest metapackage, update its PackageReference to the resolved exact version.MSTest.TestFramework and MSTest.TestAdapter to that same version.MSTest.Sdk, update the SDK version in the project or global.json pin to that same version.Run dotnet restore, then dotnet build. Collect all errors for Step 3.
Work through compilation errors systematically. Use this quick-lookup table to identify all applicable changes, then apply each fix:
| Error / Pattern in code | Breaking change | Fix |
|---|---|---|
Custom TestMethodAttribute overrides Execute | Execute removed | Change to ExecuteAsync returning Task<TestResult[]> (3.1) |
[TestMethod("name")] or custom attribute constructor | CallerInfo params added | Use DisplayName = "name" named param; propagate CallerInfo in subclasses (3.2) |
ClassCleanupBehavior.EndOfClass | Enum removed | Remove argument: just [ClassCleanup] (3.3) |
TestContext.Properties.Contains("key") | Properties is IDictionary<string, object> | Change to ContainsKey("key") (3.4) |
[Timeout(TestTimeout.Infinite)] | TestTimeout enum removed | Replace with [Timeout(int.MaxValue)] (3.5) |
TestContext.ManagedType | Property removed | Use FullyQualifiedTestClassName (3.6) |
Assert.AreEqual(a, b, "msg {0}", arg) | Message+params overloads removed | Use string interpolation: $"msg {arg}" (3.7) |
Assert.ThrowsException<T>(...) | Renamed | Replace with Assert.ThrowsExactly<T>(...) or Assert.Throws<T>(...) (3.7) |
Assert.IsInstanceOfType<T>(obj, out var t) | Out parameter removed | Use var t = Assert.IsInstanceOfType<T>(obj) (3.7) |
[ExpectedException(typeof(T))] | Attribute removed | Move assertion into test body: Assert.ThrowsExactly<T>(() => ...) (3.8) |
| Project targets net5.0, net6.0, or net7.0 | TFM dropped | Change to net8.0 or net9.0 (3.9) |
Important: Scan the entire project for ALL patterns above before starting fixes. Multiple breaking changes often coexist in the same project.
If you have custom TestMethodAttribute subclasses that override Execute, change to ExecuteAsync. This change was made because the v3 synchronous Execute API caused deadlocks when test code used async/await internally -- the synchronous wrapper would block the thread while the async operation needed that same thread to complete.
// Before (v3)
public sealed class MyTestMethodAttribute : TestMethodAttribute
{
public override TestResult[] Execute(ITestMethod testMethod)
{
// custom logic
return result;
}
}
// After (v4) -- Option A: wrap synchronous logic with Task.FromResult
public sealed class MyTestMethodAttribute : TestMethodAttribute
{
public override Task<TestResult[]> ExecuteAsync(ITestMethod testMethod)
{
// custom logic (synchronous)
return Task.FromResult(result);
}
}
// After (v4) -- Option B: make properly async
public sealed class MyTestMethodAttribute : TestMethodAttribute
{
public override async Task<TestResult[]> ExecuteAsync(ITestMethod testMethod)
{
// custom async logic
return await base.ExecuteAsync(testMethod);
}
}Use Task.FromResult when your override logic is purely synchronous. Use async/await when you call base.ExecuteAsync or other async methods.
TestMethodAttribute now uses [CallerFilePath] and [CallerLineNumber] parameters in its constructor.
If you inherit from TestMethodAttribute, propagate caller info to the base class:
public class MyTestMethodAttribute : TestMethodAttribute
{
public MyTestMethodAttribute(
[CallerFilePath] string callerFilePath = "",
[CallerLineNumber] int callerLineNumber = -1)
: base(callerFilePath, callerLineNumber)
{
}
}If the subclass has its own display-name constructor, do not pass that string to
the v4 base constructor. Propagate only caller information and assign the
DisplayName property:
public sealed class NamedTestMethodAttribute : TestMethodAttribute
{
public NamedTestMethodAttribute(
string displayName,
[CallerFilePath] string callerFilePath = "",
[CallerLineNumber] int callerLineNumber = -1)
: base(callerFilePath, callerLineNumber)
{
DisplayName = displayName;
}
}If you use [TestMethodAttribute("Custom display name")], switch to the named parameter syntax:
// Before (v3)
[TestMethodAttribute("Custom display name")]
// After (v4)
[TestMethodAttribute(DisplayName = "Custom display name")]The ClassCleanupBehavior enum is removed. In v3, this enum controlled whether class cleanup ran at end of class (EndOfClass) or end of assembly (EndOfAssembly). In v4, class cleanup always runs at end of class. Remove the enum argument:
// Before (v3)
[ClassCleanup(ClassCleanupBehavior.EndOfClass)]
public static void ClassCleanup(TestContext testContext) { }
// After (v4)
[ClassCleanup]
public static void ClassCleanup(TestContext testContext) { }If you previously used ClassCleanupBehavior.EndOfAssembly, move that cleanup logic to an [AssemblyCleanup] method instead.
TestContext.Properties changed from IDictionary to IDictionary<string, object>. Update any Contains calls to ContainsKey:
// Before (v3)
testContext.Properties.Contains("key");
// After (v4)
testContext.Properties.ContainsKey("key");The TestTimeout enum (with only TestTimeout.Infinite) is removed. Replace with int.MaxValue:
// Before (v3)
[Timeout(TestTimeout.Infinite)]
// After (v4)
[Timeout(int.MaxValue)]The TestContext.ManagedType property is removed. Use TestContext.FullyQualifiedTestClassName instead.
message and object[] parameters now accept only message. Use string interpolation instead of format strings:// Before (v3)
Assert.AreEqual(expected, actual, "Expected {0} but got {1}", expected, actual);
// After (v4)
Assert.AreEqual(expected, actual, $"Expected {expected} but got {actual}");Assert.ThrowsException APIs are renamed. Use Assert.ThrowsExactly (strict type match) or Assert.Throws (accepts derived exception types):// Before (v3)
Assert.ThrowsException<InvalidOperationException>(() => DoSomething());
// After (v4) -- exact type match (same behavior as old ThrowsException)
Assert.ThrowsExactly<InvalidOperationException>(() => DoSomething());
// After (v4) -- also catches derived exception types
Assert.Throws<InvalidOperationException>(() => DoSomething());Assert.IsInstanceOfType<T>(x, out var t) changes to var t = Assert.IsInstanceOfType<T>(x):// Before (v3)
Assert.IsInstanceOfType<MyType>(obj, out var typed);
// After (v4)
var typed = Assert.IsInstanceOfType<MyType>(obj);Apply this assignment rewrite to every occurrence, preserving the concrete asserted type and all
later uses of the typed variable. When source is available, show or edit the actual method rather
than substituting a generic MyType example, then verify that the project compiles.
object.The [ExpectedException] attribute is removed in v4. In MSTest 3.2, the MSTEST0006 analyzer was introduced to flag [ExpectedException] usage and suggest migrating to Assert.ThrowsExactly while still on v3 (a non-breaking change). In v4, the attribute is gone entirely. Migrate to Assert.ThrowsExactly:
// Before (v3)
[ExpectedException(typeof(InvalidOperationException))]
[TestMethod]
public void TestMethod()
{
MyCall();
}
// After (v4)
[TestMethod]
public void TestMethod()
{
Assert.ThrowsExactly<InvalidOperationException>(() => MyCall());
}When the test has setup code before the throwing call, wrap only the throwing call in the lambda -- keep Arrange/Act separation clear:
// Before (v3)
[ExpectedException(typeof(ArgumentNullException))]
[TestMethod]
public void Validate_NullInput_Throws()
{
var service = new ValidationService();
service.Validate(null); // throws here
}
// After (v4)
[TestMethod]
public void Validate_NullInput_Throws()
{
var service = new ValidationService();
Assert.ThrowsExactly<ArgumentNullException>(() => service.Validate(null));
}For async test methods, use Assert.ThrowsExactlyAsync:
// Before (v3)
[ExpectedException(typeof(HttpRequestException))]
[TestMethod]
public async Task FetchData_BadUrl_Throws()
{
await client.GetAsync("https://localhost:0");
}
// After (v4)
[TestMethod]
public async Task FetchData_BadUrl_Throws()
{
await Assert.ThrowsExactlyAsync<HttpRequestException>(
() => client.GetAsync("https://localhost:0"));
}If [ExpectedException] used the AllowDerivedTypes property, use Assert.ThrowsAsync<T> (base type matching) instead of Assert.ThrowsExactlyAsync<T> (exact type matching).
For a focused migration, convert every attributed method in the supplied source, wrap only the statement expected to throw, preserve arrange/setup statements outside the lambda, and run the affected tests. A prose-only API substitution is incomplete when editable project files are present.
MSTest v4 supports .NET 8 and later and .NET Framework 4.6.2 and later. Platform-specific supported targets also include uap10.0.16299 (UWP), with modern UWP and WinUI using their corresponding supported Windows-specific .NET TFMs. .NET Core 3.1 through .NET 7 are dropped.
If the test project targets an unsupported framework, update TargetFramework:
<!-- Before -->
<TargetFramework>net6.0</TargetFramework>
<!-- After -->
<TargetFramework>net8.0</TargetFramework>The UnfoldingStrategy property (introduced in MSTest 3.7) has moved from individual data source attributes (DataRowAttribute, DynamicDataAttribute) to TestMethodAttribute.
The ConditionBaseAttribute.ShouldRun property is renamed to IsConditionMet.
Several types previously public are now internal or removed:
MSTestDiscoverer, MSTestExecutor, AssemblyResolver, LogMessageListenerTestExecutionManager, TestMethodInfo, TestResultExtensionsUnitTestOutcomeExtensions, GenericParameterHelperITestMethod in PlatformServices assembly (the one in TestFramework is unchanged)If your code references any of these, find alternative approaches or remove the dependency.
These changes won't cause build errors but may affect test runtime behavior.
| Symptom | Cause | Fix |
|---|---|---|
| Tests show as new in Azure DevOps / test history lost | TestCase.Id generation changed (4.3) | No code fix; history will re-baseline |
TestContext.TestName throws in [ClassInitialize] | v4 enforces lifecycle scope (4.2) | Move access to [TestInitialize] or test methods |
| Tests not discovered / discovery failures | TreatDiscoveryWarningsAsErrors now true (4.4) | Fix warnings, or set to false in .runsettings |
| Tests hang that didn't before | AppDomain disabled by default (4.1) | Set DisableAppDomain to false in .runsettings RunConfiguration |
| vstest.console can't find tests with MSTest.Sdk after the v4 upgrade | MSTest.Sdk defaults to MTP; v4 stopped adding Microsoft.NET.Test.Sdk in MTP mode (4.5) | Add an explicit package while preserving MTP, set UseVSTest, or switch CI to dotnet test |
| New warnings from analyzers | Analyzer severities upgraded (4.6) | Fix warnings or suppress in .editorconfig |
AppDomains are disabled by default. On .NET Framework, when running inside testhost (the default for dotnet test and VS), MSTest re-enables AppDomains automatically. If you need to explicitly control AppDomain isolation, set it via .runsettings:
<RunSettings>
<RunConfiguration>
<DisableAppDomain>false</DisableAppDomain>
</RunConfiguration>
</RunSettings>MSTest v4 now throws when accessing test-specific properties in the wrong lifecycle stage:
TestContext.FullyQualifiedTestClassName -- cannot be accessed in [AssemblyInitialize]TestContext.TestName -- cannot be accessed in [AssemblyInitialize] or [ClassInitialize]Fix: Move any code that accesses TestContext.TestName from [ClassInitialize] to [TestInitialize] or individual test methods, where per-test context is available. Do not replace TestName with FullyQualifiedTestClassName as a workaround -- they have different semantics.
The generation algorithm for TestCase.Id has changed to fix long-standing bugs. This may affect Azure DevOps test result tracking (e.g., test failure tracking over time). There is no code fix needed, but be aware of test result history discontinuity.
v4 uses stricter defaults. Discovery warnings are now treated as errors, which means tests that previously ran despite discovery issues may now fail entirely. If you see unexpected test failures after upgrading (not build errors, but tests not being discovered), check for discovery warnings. To restore v3 behavior while you investigate:
<RunSettings>
<MSTest>
<TreatDiscoveryWarningsAsErrors>false</TreatDiscoveryWarningsAsErrors>
</MSTest>
</RunSettings>Recommended: Fix the underlying discovery warnings rather than suppressing this setting.
MSTest.Sdk defaults to Microsoft.Testing.Platform (MTP) mode. MSTest.Sdk v3
still added Microsoft.NET.Test.Sdk in that mode; v4 removes the unnecessary
reference. A CI pipeline that separately invokes vstest.console can therefore
drop to zero discovered tests immediately after the v4 upgrade.
Option A -- Preserve MTP and transitional VSTest discovery: Add the exact
compatible Microsoft.NET.Test.Sdk package explicitly. This is the least
disruptive fix when MTP remains the primary runner but an existing
vstest.console job cannot be removed yet:
Use a direct PackageReference with the exact compatible version resolved from
the configured feed. Under Central Package Management, add or update the
Microsoft.NET.Test.Sdk PackageVersion in Directory.Packages.props and keep
the project reference versionless. Do not copy a fixed example version.
Verify with the actual vstest.console command; a passing dotnet test MTP run
does not prove VSTest discovery.
Option B -- Switch the project to VSTest mode: Set the UseVSTest property.
MSTest.Sdk then adds Microsoft.NET.Test.Sdk:
<PropertyGroup>
<UseVSTest>true</UseVSTest>
</PropertyGroup>Keep the resolved exact MSTest.Sdk v4 pin from Step 2; this option changes the runner, not the
selected MSTest version or target framework.
Option C -- Switch CI to dotnet test: Replace vstest.console invocations in your CI pipeline with dotnet test. This works natively with MTP and is the recommended long-term approach for MSTest.Sdk projects.
Do not say this behavior predates v4: removal of the transitive
Microsoft.NET.Test.Sdk reference in MTP mode is one of the v4 behavioral
breaking changes.
Multiple analyzers have been upgraded from Info to Warning by default:
Review and fix any new warnings, or suppress them in .editorconfig if intentional.
dotnet build -- confirm zero errors and review any new warningsdotnet test -- confirm all tests passTestCase.Id changes may affect history continuitydotnet testTestMethodAttribute subclasses updated for ExecuteAsync and CallerInfoExpectedExceptionAttribute replaced with Assert.ThrowsExactlyAssert.ThrowsException replaced with Assert.ThrowsExactly (or Assert.Throws)ClassCleanupBehavior enum usages removedTestContext.Properties.Contains updated to ContainsKeywriting-mstest-tests -- for modern MSTest v4 assertion APIs and test authoring best practicesrun-tests -- for running tests after migration| Pitfall | Solution |
|---|---|
Custom TestMethodAttribute still overrides Execute | Change to ExecuteAsync returning Task<TestResult[]> |
TestMethodAttribute("display name") no longer compiles | Use TestMethodAttribute(DisplayName = "display name") |
ClassCleanupBehavior enum not found | Remove the enum argument; [ClassCleanup] now always runs at end of class. For end-of-assembly cleanup, use [AssemblyCleanup] |
TestContext.Properties.Contains missing | Use ContainsKey -- Properties is now IDictionary<string, object> |
ExpectedException attribute not found | Replace with Assert.ThrowsExactly<T>(() => ...) inside the test body |
Assert.ThrowsException not found | Replace with Assert.ThrowsExactly (or Assert.Throws for derived types) |
Assert.AreEqual with format string args fails | Use string interpolation: $"message {value}" |
| Tests hang that didn't before | AppDomain is disabled by default; on .NET Fx in testhost it is re-enabled automatically |
| Azure DevOps test history breaks | Expected -- TestCase.Id generation changed; no code fix, results will re-baseline |
| Discovery warnings now fail the run | TreatDiscoveryWarningsAsErrors is true by default; fix the discovery warnings |
| Net6.0/net7.0 targets don't compile | Update to net8.0 -- MSTest v4 supports net8.0, net9.0, net462, uap10.0.16299, modern UWP, and WinUI |
© dotnet, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 of dotnet/skills.
Open the folder on GitHubat commit 1d40f95
We found 2 copies of this SKILL.md (exact, near-identical or edited) in other folders, from 1 other GitHub owner. This page covers the copy in dotnet/skills, which our catalogue first saw on October 7, 2026.
Migrate Mstest V3 To V4 next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Migrate Mstest V3 To V4 this skilldotnet/skills | 5.6k | 1 repos | ~7.2k | Automated safety check: Pass | MIT | |
| Minimax DOCXpoco-ai/poco-claw | 1.4k | 7 repos | ~3.9k | Automated safety check: Pass | MIT | |
| Microsoft Skill CreatorMicrosoftDocs/mcp | 1.9k | 3 repos | ~2.1k | Automated safety check: Pass | CC-BY-4.0 | |
| Speckit ConstitutionWeihanLi/WeihanLi.Common | 242 | 12 repos | ~2.1k | Automated safety check: Pass | Apache-2.0 | |
| Copilot Session Failure Analysisdotnet/maui | 23k | — | ~3.4k | Automated safety check: Pass | MIT | |
| Update .NET OS Packagesdotnet/core | 22k | — | ~2.3k | Automated safety check: Pass | MIT |
poco-ai/poco-claw
Professional DOCX document creation, editing, and formatting using OpenXML SDK (.NET).
MicrosoftDocs/mcp
Create agent skills for Microsoft technologies using official documentation.
WeihanLi/WeihanLi.Common
Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync.
dotnet/maui
Mines local Copilot CLI session logs for dotnet/maui to rank costly or failing runs, tag recurring failure modes, propose repo edits and emit guard evals.
dotnet/core
Audits and updates os-packages.json files listing the Linux packages each .NET release needs per distro, then regenerates the Markdown from the JSON.
MicrosoftDocs/mcp
Find working code samples, verify API signatures, and fix Microsoft SDK errors using official docs.
dotnet/skills
Resolves .NET runtime frames in Apple .ips crash logs to function names, source files and line numbers using dSYM symbols, atos and the Microsoft symbol server.
dotnet/skills
Scans C# and .NET code for about 50 performance anti-patterns and reports prioritized findings with concrete fixes, at a scan depth you choose.
dotnet/skills
Resolves native crash frames from .NET Android tombstones to function names, source files and line numbers using BuildIds, Microsoft's symbol server and llvm-symbolizer.
dotnet/skills
Activate this skill when BenchmarkDotNet (BDN) is involved in the task — creating, running, configuring, or reviewing BDN benchmarks.
dotnet/skills
Makes .NET projects compatible with Native AOT and trimming by resolving IL trim and AOT analyzer warnings through annotations rather than suppressions.
dotnet/skills
Configures automatic crash dumps or captures dumps from running processes for modern .NET apps on Linux, macOS and Windows, including Docker and Kubernetes.
Works with
Use this skill before answering, planning, or editing any MSTest 3.x-to-4.x upgrade or post-upgrade failure. Migrate Mstest V3 To V4 is an agent skill from dotnet/skills, published by the product's own GitHub organization.x upgrade or post-upgrade failure.
Migrate Mstest V3 To V4 fits situations like: include MSTest v4 breaking changes; CS0507/CS0103/CS1061/CS1615; custom TestMethodAttribute; classCleanupBehavior.
Run `npx skills add dotnet/skills --skill migrate-mstest-v3-to-v4 -a claude-code`. Or copy the skill folder (plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 in dotnet/skills) into .claude/skills/migrate-mstest-v3-to-v4 in your project. Claude Code loads it when a task matches its description.
Run `npx skills add dotnet/skills --skill migrate-mstest-v3-to-v4 -a codex`. Or copy the skill folder (plugins/dotnet-test-migration/skills/migrate-mstest-v3-to-v4 in dotnet/skills) into .agents/skills/migrate-mstest-v3-to-v4 in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add dotnet/skills --skill migrate-mstest-v3-to-v4 -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/migrate-mstest-v3-to-v4, .gemini/skills/migrate-mstest-v3-to-v4, .github/skills/migrate-mstest-v3-to-v4 and .opencode/skills/migrate-mstest-v3-to-v4 in your project.
Going by SKILL.md and its folder, Migrate Mstest V3 To V4 needs the command-line tools its instructions call (dotnet).
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Migrate Mstest V3 To V4 is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
About 7.2k tokens (SKILL.md is roughly 29k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Migrate Mstest V3 To V4: Minimax DOCX (poco-ai/poco-claw, 1.4k stars), Microsoft Skill Creator (MicrosoftDocs/mcp, 1.9k stars), Speckit Constitution (WeihanLi/WeihanLi.Common, 242 stars) and Copilot Session Failure Analysis (dotnet/maui, 23k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
dotnet (a GitHub organization, an official publisher) maintains it in dotnet/skills, which has 5,594 GitHub stars. The repository holds 70 skills in this directory. The repository was last updated on October 9, 2026.
Source: dotnet/skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.