Agent skill

Migrate Mstest V3 To V4

by runceel in runceel/ReactiveProperty

Fix build errors and breaking changes after upgrading MSTest from v3 to v4, or plan a complete MSTest v3-to-v4 migration.

MITAuto-check passed

Install Migrate Mstest V3 To V4

skills CLI
$ npx skills add runceel/ReactiveProperty --skill migrate-mstest-v3-to-v4 -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install runceel/ReactiveProperty migrate-mstest-v3-to-v4 --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/runceel/ReactiveProperty.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/migrate-mstest-v3-to-v4 .claude/skills/migrate-mstest-v3-to-v4 && rm -rf skills-src

Use ~/.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/

Facts

Skill name
migrate-mstest-v3-to-v4
GitHub stars
944
Token cost
~6k tokens
SKILL.md length
2,220 words
Files
1
Skills in repo
13
Repo updated
First seen
Licence
MIT

At a glance

Fix build errors and breaking changes after upgrading MSTest from v3 to v4, or plan a complete MSTest v3-to-v4 migration.

  • Works in 5 steps: Assess the project → Update packages to MSTest v4 → Resolve source breaking changes → …
  • User says upgrade to MSTest v4
  • SKILL.md covers When to Use, When Not to Use, Inputs and Response Guidelines, plus 4 more sections
  • Calls dotnet

What it does

Migrate Mstest V3 To V4 is an agent skill from runceel/ReactiveProperty. Fix build errors and breaking changes after upgrading MSTest from v3 to v4, or plan a complete MSTest v3-to-v4 migration. Use when user says "upgrade to MSTest v4", "MSTest 4 migration", "MSTest v4 breaking changes", "tests don't compile after upgrading MSTest", or has errors CS0507, CS0103, CS1061, CS1615 after updating MSTest packages from 3.x to 4.x. USE FOR: Execute to ExecuteAsync, CallerInfo constructor on TestMethodAttribute, sealed custom attributes, ClassCleanupBehavior removal, TestContext.Properties…

Its SKILL.md is about 6k 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: ReactiveProperty provides MVVM and asynchronous support features under Reactive Extensions. Target frameworks are .NET 6+, .NET Framework 4.7.2 and .NET Standard 2.0. The licence is MIT.

When your agent uses it

  • User says upgrade to MSTest v4
  • MSTest 4 migration
  • MSTest v4 breaking changes
  • Tests dont compile after upgrading MSTest

Example prompts

  • “upgrade to MSTest v4”
  • “MSTest 4 migration”
  • “MSTest v4 breaking changes”
  • “/migrate-mstest-v3-to-v4”

Workflow steps

5 steps, taken from the step headings in SKILL.md.

  1. Assess the project
  2. Update packages to MSTest v4
  3. Resolve source breaking changes
  4. Address behavioral changes
  5. Verify

What it can do on your machine

Read from SKILL.md and the folder at commit e7e6474. It shows what the files ask for, not the result of running them.

  • Tool permissions

    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.

  • Runs code

    Shell commands in SKILL.md call:

    • dotnet

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Migrate Mstest V3 To V4 loads about 6k tokens when it runs. Until then it costs about 262 tokens; SKILL.md has 2,220 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~262
When it runs · the whole SKILL.md, loaded when a task matches
~6k

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.

Safety

Auto-check passed

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.

SKILL.md

The full file from runceel/ReactiveProperty at commit e7e6474, republished under its MIT licence (© runceel). 2,220 words, ~6,011 tokens.

Download SKILL.mdSave it as .claude/skills/migrate-mstest-v3-to-v4/SKILL.md (or your agent's skills folder).
name
migrate-mstest-v3-to-v4
description
Fix build errors and breaking changes after upgrading MSTest from v3 to v4, or plan a complete MSTest v3-to-v4 migration. Use when user says "upgrade to MSTest v4", "MSTest 4 migration", "MSTest v4 breaking changes", "tests don't compile after upgrading MSTest", or has errors CS0507, CS0103, CS1061, CS1615 after updating MSTest packages from 3.x to 4.x. USE FOR: Execute to ExecuteAsync, CallerInfo constructor on TestMethodAttribute, sealed custom attributes, ClassCleanupBehavior removal, TestContext.Properties Contains to ContainsKey, Assert.ThrowsException to ThrowsExactly, Assert.IsInstanceOfType out parameter removal, ExpectedExceptionAttribute removal, TestTimeout enum removal, [TestMethod("name")] to DisplayName syntax, TreatDiscoveryWarningsAsErrors, TestContext.TestName in ClassInitialize, MSTest.Sdk MTP changes, dropped TFMs (net6.0/net7.0 to net8.0+). DO NOT USE FOR: migrating from MSTest v1/v2 to v3 (use migrate-mstest-v1v2-to-v3 first), migrating between test frameworks, or general .NET upgrades.
metadata.github-path
plugins/dotnet-test/skills/migrate-mstest-v3-to-v4
metadata.github-pinned
v1.0.0
metadata.github-ref
refs/tags/v1.0.0
metadata.github-repo
https://github.com/dotnet/skills
metadata.github-tree-sha
3b7094e42ae389b19d1e5770749e42dfcb2bf8e8

MSTest v3 -> v4 Migration

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.

When to Use

  • Upgrading MSTest.TestFramework, MSTest.TestAdapter, or MSTest metapackage from 3.x to 4.x
  • Upgrading MSTest.Sdk from 3.x to 4.x
  • Fixing build errors after updating to MSTest v4 packages
  • Resolving behavioral changes in test execution after upgrading to MSTest v4
  • Updating custom TestMethodAttribute or ConditionBaseAttribute implementations for v4

When Not to Use

  • The project already uses MSTest v4 and builds cleanly -- migration is done
  • Upgrading from MSTest v1 or v2 -- use migrate-mstest-v1v2-to-v3 first, then return here
  • The project does not use MSTest
  • Migrating between test frameworks (e.g., MSTest to xUnit or NUnit)

Inputs

InputRequiredDescription
Project or solution pathYesThe .csproj, .sln, or .slnx entry point containing MSTest test projects
Build commandNoHow to build (e.g., dotnet build, a repo build script). Auto-detect if not provided
Test commandNoHow to run tests (e.g., dotnet test). Auto-detect if not provided

Response Guidelines

  • Always identify the current version first: Before recommending any migration steps, explicitly state the current MSTest version detected in the project (e.g., "Your project uses MSTest v3 (3.8.0)"). This confirms you've read the project files and grounds the migration advice.
  • Focused fix requests (user has specific compilation errors after upgrading): Address only the relevant breaking changes from Step 3. Always provide concrete fixed code using the user's actual types and method names — show a complete, copy-pasteable code snippet, not just a description of what to change. For custom 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). Do not walk through the entire migration workflow.
  • "What to expect" questions (user asks about breaking changes before upgrading): Present ALL major breaking changes from the Step 3 quick-lookup table -- not just the ones visible in the current code. For each, provide a one-line fix summary. Also mention key behavioral changes from Step 4 (especially TestCase.Id history impact and TreatDiscoveryWarningsAsErrors default). If project code is available, highlight which changes apply directly.
  • Full migration requests (user wants complete migration): Follow the complete workflow below.
  • Behavioral/runtime symptom reports (user describes test execution differences without build errors): Match described symptoms to the behavioral changes table in Step 4. Provide targeted, symptom-specific advice. Mention other behavioral changes the user should watch for. Do not walk through source breaking changes unless the user also has build errors.
  • CI/test-discovery issues (tests not discovered, vstest.console stopped working, CI pipeline failures after upgrading): Focus on 4.5 (MSTest.Sdk defaults to MTP mode, which does not include Microsoft.NET.Test.Sdk -- needed for vstest.console) and 4.4 (TreatDiscoveryWarningsAsErrors). Explain the root cause clearly and give both fix options (add Microsoft.NET.Test.Sdk package or switch to dotnet test). Do not walk through the full migration workflow.
  • Explanatory questions (user asks "is this a known change?", "what else should I watch out for?"): Explain the relevant changes and advise. Mention related changes the user might encounter next. Do not prescribe a full migration procedure.

Workflow

Commit strategy: Commit at each logical boundary -- after updating packages (Step 2), after resolving source breaking changes (Step 3), after addressing behavioral changes (Step 4). This keeps each commit focused and reviewable.

Step 1: Assess the project
  1. Identify the current MSTest version by checking package references for MSTest, MSTest.TestFramework, MSTest.TestAdapter, or MSTest.Sdk in .csproj, Directory.Build.props, or Directory.Packages.props.
  2. Confirm the project is on MSTest v3 (3.x). If on v1 or v2, use migrate-mstest-v1v2-to-v3 first.
  3. Check target framework(s) -- MSTest v4 drops support for .NET Core 3.1 through .NET 7. Supported target frameworks are: net8.0, net9.0, net462 (.NET Framework 4.6.2+), uap10.0.16299 (UWP), net9.0-windows10.0.17763.0 (modern UWP), and net8.0-windows10.0.18362.0 (WinUI).
  4. Check for custom TestMethodAttribute subclasses -- these require changes in v4.
  5. Check for usages of ExpectedExceptionAttribute -- removed in v4 (deprecated since v3 with analyzer MSTEST0006).
  6. Check for usages of Assert.ThrowsException (deprecated) -- removed in v4.
  7. Run a clean build to establish a baseline of existing errors/warnings.
Step 2: Update packages to MSTest v4

If using the MSTest metapackage:

xml
<PackageReference Include="MSTest" Version="4.1.0" />

If using individual packages:

xml
<PackageReference Include="MSTest.TestFramework" Version="4.1.0" />
<PackageReference Include="MSTest.TestAdapter" Version="4.1.0" />

If using MSTest.Sdk:

xml
<Project Sdk="MSTest.Sdk/4.1.0">

Run dotnet restore, then dotnet build. Collect all errors for Step 3.

Step 3: Resolve source breaking changes

Work through compilation errors systematically. Use this quick-lookup table to identify all applicable changes, then apply each fix:

Error / Pattern in codeBreaking changeFix
Custom TestMethodAttribute overrides ExecuteExecute removedChange to ExecuteAsync returning Task<TestResult[]> (3.1)
[TestMethod("name")] or custom attribute constructorCallerInfo params addedUse DisplayName = "name" named param; propagate CallerInfo in subclasses (3.2)
ClassCleanupBehavior.EndOfClassEnum removedRemove 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 removedReplace with [Timeout(int.MaxValue)] (3.5)
TestContext.ManagedTypeProperty removedUse FullyQualifiedTestClassName (3.6)
Assert.AreEqual(a, b, "msg {0}", arg)Message+params overloads removedUse string interpolation: $"msg {arg}" (3.7)
Assert.ThrowsException<T>(...)RenamedReplace with Assert.ThrowsExactly<T>(...) or Assert.Throws<T>(...) (3.7)
Assert.IsInstanceOfType<T>(obj, out var t)Out parameter removedUse var t = Assert.IsInstanceOfType<T>(obj) (3.7)
[ExpectedException(typeof(T))]Attribute removedMove assertion into test body: Assert.ThrowsExactly<T>(() => ...) (3.8)
Project targets net5.0, net6.0, or net7.0TFM droppedChange 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.

3.1 TestMethodAttribute.Execute -> ExecuteAsync

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.

csharp
// 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.

3.2 TestMethodAttribute CallerInfo constructor

TestMethodAttribute now uses [CallerFilePath] and [CallerLineNumber] parameters in its constructor.

If you inherit from TestMethodAttribute, propagate caller info to the base class:

csharp
public class MyTestMethodAttribute : TestMethodAttribute
{
    public MyTestMethodAttribute(
        [CallerFilePath] string callerFilePath = "",
        [CallerLineNumber] int callerLineNumber = -1)
        : base(callerFilePath, callerLineNumber)
    {
    }
}

If you use [TestMethodAttribute("Custom display name")], switch to the named parameter syntax:

csharp
// Before (v3)
[TestMethodAttribute("Custom display name")]

// After (v4)
[TestMethodAttribute(DisplayName = "Custom display name")]
3.3 ClassCleanupBehavior enum removed

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:

csharp
// 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.

3.4 TestContext.Properties type change

TestContext.Properties changed from IDictionary to IDictionary<string, object>. Update any Contains calls to ContainsKey:

csharp
// Before (v3)
testContext.Properties.Contains("key");

// After (v4)
testContext.Properties.ContainsKey("key");
3.5 TestTimeout enum removed

The TestTimeout enum (with only TestTimeout.Infinite) is removed. Replace with int.MaxValue:

csharp
// Before (v3)
[Timeout(TestTimeout.Infinite)]

// After (v4)
[Timeout(int.MaxValue)]
3.6 TestContext.ManagedType removed

The TestContext.ManagedType property is removed. Use TestContext.FullyQualifiedTestClassName instead.

3.7 Assert API signature changes
  • Message + params removed: Assert methods that accepted both message and object[] parameters now accept only message. Use string interpolation instead of format strings:
csharp
// 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 renamed: The Assert.ThrowsException APIs are renamed. Use Assert.ThrowsExactly (strict type match) or Assert.Throws (accepts derived exception types):
csharp
// 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 out parameter changed: Assert.IsInstanceOfType<T>(x, out var t) changes to var t = Assert.IsInstanceOfType<T>(x):
csharp
// Before (v3)
Assert.IsInstanceOfType<MyType>(obj, out var typed);

// After (v4)
var typed = Assert.IsInstanceOfType<MyType>(obj);
  • Assert.AreEqual for IEquatable<T> removed: If you get generic type inference errors, explicitly specify the type argument as object.
3.8 ExpectedExceptionAttribute removed

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:

csharp
// 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:

csharp
// 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:

csharp
// 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).

3.9 Dropped target frameworks

MSTest v4 supports: net8.0, net9.0, net462 (.NET Framework 4.6.2+), uap10.0.16299 (UWP), net9.0-windows10.0.17763.0 (modern UWP), and net8.0-windows10.0.18362.0 (WinUI). All other frameworks are dropped -- including net5.0, net6.0, net7.0, and netcoreapp3.1.

If the test project targets an unsupported framework, update TargetFramework:

xml
<!-- Before -->
<TargetFramework>net6.0</TargetFramework>

<!-- After -->
<TargetFramework>net8.0</TargetFramework>
3.10 Unfolding strategy moved to TestMethodAttribute

The UnfoldingStrategy property (introduced in MSTest 3.7) has moved from individual data source attributes (DataRowAttribute, DynamicDataAttribute) to TestMethodAttribute.

Show full SKILL.md (882 more words)Show less
3.11 ConditionBaseAttribute.ShouldRun renamed

The ConditionBaseAttribute.ShouldRun property is renamed to IsConditionMet.

3.12 Internal/removed types

Several types previously public are now internal or removed:

  • MSTestDiscoverer, MSTestExecutor, AssemblyResolver, LogMessageListener
  • TestExecutionManager, TestMethodInfo, TestResultExtensions
  • UnitTestOutcomeExtensions, GenericParameterHelper
  • ITestMethod in PlatformServices assembly (the one in TestFramework is unchanged)

If your code references any of these, find alternative approaches or remove the dependency.

Step 4: Address behavioral changes

These changes won't cause build errors but may affect test runtime behavior.

SymptomCauseFix
Tests show as new in Azure DevOps / test history lostTestCase.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 failuresTreatDiscoveryWarningsAsErrors now true (4.4)Fix warnings, or set to false in .runsettings
Tests hang that didn't beforeAppDomain disabled by default (4.1)Set DisableAppDomain to false in .runsettings RunConfiguration
vstest.console can't find tests with MSTest.SdkMSTest.Sdk defaults to MTP; Microsoft.NET.Test.Sdk only added in VSTest mode (4.5)Add explicit package reference or switch to dotnet test
New warnings from analyzersAnalyzer severities upgraded (4.6)Fix warnings or suppress in .editorconfig
4.1 DisableAppDomain defaults to true

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:

xml
<RunSettings>
  <RunConfiguration>
    <DisableAppDomain>false</DisableAppDomain>
  </RunConfiguration>
</RunSettings>
4.2 TestContext throws when used incorrectly

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.

4.3 TestCase.Id generation changed

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.

4.4 TreatDiscoveryWarningsAsErrors defaults to true

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:

xml
<RunSettings>
  <MSTest>
    <TreatDiscoveryWarningsAsErrors>false</TreatDiscoveryWarningsAsErrors>
  </MSTest>
</RunSettings>

Recommended: Fix the underlying discovery warnings rather than suppressing this setting.

4.5 MSTest.Sdk and vstest.console compatibility

MSTest.Sdk defaults to Microsoft.Testing.Platform (MTP) mode. In MTP mode, MSTest.Sdk does not add a reference to Microsoft.NET.Test.Sdk -- it only adds it in VSTest mode. This is not a v4-specific change; it applies to MSTest.Sdk v3 as well. Without Microsoft.NET.Test.Sdk, vstest.console cannot discover or run tests and will silently find zero tests. This commonly surfaces during migration when a CI pipeline uses vstest.console but the project uses MSTest.Sdk in its default MTP mode.

Option A -- Switch to VSTest mode: Set the UseVSTest property. MSTest.Sdk will then automatically add Microsoft.NET.Test.Sdk:

xml
<Project Sdk="MSTest.Sdk/4.1.0">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <UseVSTest>true</UseVSTest>
  </PropertyGroup>
</Project>

Option B -- 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.

If you need VSTest during a transition period, Option A works without changing CI pipelines.

4.6 Analyzer severity changes

Multiple analyzers have been upgraded from Info to Warning by default:

  • MSTEST0001, MSTEST0007, MSTEST0017, MSTEST0023, MSTEST0024, MSTEST0025
  • MSTEST0030, MSTEST0031, MSTEST0032, MSTEST0035, MSTEST0037, MSTEST0045

Review and fix any new warnings, or suppress them in .editorconfig if intentional.

Step 5: Verify
  1. Run dotnet build -- confirm zero errors and review any new warnings
  2. Run dotnet test -- confirm all tests pass
  3. Compare test results (pass/fail counts) to the pre-migration baseline
  4. If using Azure DevOps test tracking, be aware that TestCase.Id changes may affect history continuity
  5. Check that no tests were silently dropped due to stricter discovery

Validation

  • All MSTest packages updated to 4.x
  • Project builds with zero errors
  • All tests pass with dotnet test
  • Custom TestMethodAttribute subclasses updated for ExecuteAsync and CallerInfo
  • ExpectedExceptionAttribute replaced with Assert.ThrowsExactly
  • Assert.ThrowsException replaced with Assert.ThrowsExactly (or Assert.Throws)
  • ClassCleanupBehavior enum usages removed
  • TestContext.Properties.Contains updated to ContainsKey
  • All target frameworks are net8.0+, net9.0, net462+, uap10.0.16299, or WinUI
  • Behavioral changes reviewed and addressed
  • No tests were lost during migration (compare test counts)
  • writing-mstest-tests -- for modern MSTest v4 assertion APIs and test authoring best practices
  • run-tests -- for running tests after migration

Common Pitfalls

PitfallSolution
Custom TestMethodAttribute still overrides ExecuteChange to ExecuteAsync returning Task<TestResult[]>
TestMethodAttribute("display name") no longer compilesUse TestMethodAttribute(DisplayName = "display name")
ClassCleanupBehavior enum not foundRemove the enum argument; [ClassCleanup] now always runs at end of class. For end-of-assembly cleanup, use [AssemblyCleanup]
TestContext.Properties.Contains missingUse ContainsKey -- Properties is now IDictionary<string, object>
ExpectedException attribute not foundReplace with Assert.ThrowsExactly<T>(() => ...) inside the test body
Assert.ThrowsException not foundReplace with Assert.ThrowsExactly (or Assert.Throws for derived types)
Assert.AreEqual with format string args failsUse string interpolation: $"message {value}"
Tests hang that didn't beforeAppDomain is disabled by default; on .NET Fx in testhost it is re-enabled automatically
Azure DevOps test history breaksExpected -- TestCase.Id generation changed; no code fix, results will re-baseline
Discovery warnings now fail the runTreatDiscoveryWarningsAsErrors is true by default; fix the discovery warnings
Net6.0/net7.0 targets don't compileUpdate to net8.0 -- MSTest v4 supports net8.0, net9.0, net462, uap10.0.16299, modern UWP, and WinUI

© runceel, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .agents/skills/migrate-mstest-v3-to-v4 of runceel/ReactiveProperty.

Open the folder on GitHubat commit e7e6474

Compare with similar skills

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.

Migrate Mstest V3 To V4 compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Migrate Mstest V3 To V4 this skillrunceel/ReactiveProperty944—~6kAutomated safety check: PassMIT
Minimax DOCXpoco-ai/poco-claw1.4k7 repos~3.9kAutomated safety check: PassMIT
Microsoft Skill CreatorMicrosoftDocs/mcp1.9k3 repos~2.1kAutomated safety check: PassCC-BY-4.0
Speckit ConstitutionWeihanLi/WeihanLi.Common24212 repos~2.1kAutomated safety check: PassApache-2.0
Copilot Session Failure Analysisdotnet/maui23k—~3.4kAutomated safety check: PassMIT
Update .NET OS Packagesdotnet/core22k—~2.3kAutomated safety check: PassMIT

Similar skills

  • Minimax DOCX

    poco-ai/poco-claw

    Professional DOCX document creation, editing, and formatting using OpenXML SDK (.NET).

    1.4k GitHub starsUsed in 7 repos~3.9k tokens
    Documents & OfficeAuto-check passed
  • Microsoft Skill Creator

    MicrosoftDocs/mcp

    Official

    Create agent skills for Microsoft technologies using official documentation.

    1.9k GitHub starsUsed in 3 repos~2.1k tokens
    Agent WorkflowsAuto-check passed
  • Speckit Constitution

    WeihanLi/WeihanLi.Common

    Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync.

    242 GitHub starsUsed in 12 repos~2.1k tokens
    DevelopmentAuto-check passed
  • 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.

    23k GitHub stars~3.4k tokensUpdated yesterday
    Agent WorkflowsAuto-check passed
  • Official

    Audits and updates os-packages.json files listing the Linux packages each .NET release needs per distro, then regenerates the Markdown from the JSON.

    22k GitHub stars~2.3k tokensUpdated 2 days ago
    DevelopmentAuto-check passed
  • Microsoft Code Reference

    MicrosoftDocs/mcp

    Official

    Find working code samples, verify API signatures, and fix Microsoft SDK errors using official docs.

    1.9k GitHub starsUsed in 3 repos~1.1k tokens
    DevelopmentAuto-check passed

More from runceel/ReactiveProperty

All 13 skills in this repo
  • Msbuild Antipatterns

    runceel/ReactiveProperty

    Catalog of MSBuild anti-patterns with detection rules and fix recipes.

    944 GitHub stars~3.7k tokensUpdated 1 mo ago
    Auto-check passed
  • Binlog Failure Analysis

    runceel/ReactiveProperty

    Analyze MSBuild binary logs to diagnose build failures by replaying binlogs to searchable text logs.

    944 GitHub stars~1.1k tokensUpdated 1 mo ago
    Auto-check passed
  • Coverage Analysis

    runceel/ReactiveProperty

    Automated, project-wide code coverage and CRAP (Change Risk Anti-Patterns) score analysis for .NET projects with existing unit tests.

    944 GitHub stars~5.9k tokensUpdated 1 mo ago
    Auto-check: warnings
  • Development Workflow

    runceel/ReactiveProperty

    ReactiveProperty repository development policy. An agent skill from runceel/ReactiveProperty.

    944 GitHub stars~1.4k tokensUpdated 1 mo ago
    Auto-check passed
  • Dotnet10 Features

    runceel/ReactiveProperty

    Reference for the .NET 10 / C 14 features that are relevant to the ReactiveProperty repository.

    944 GitHub stars~2.7k tokensUpdated 1 mo ago
    Auto-check passed
  • Migrate Vstest To Mtp

    runceel/ReactiveProperty

    Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP).

    944 GitHub stars~4.3k tokensUpdated 1 mo ago
    Auto-check passed

Works with

Questions about Migrate Mstest V3 To V4

What does Migrate Mstest V3 To V4 do?

Fix build errors and breaking changes after upgrading MSTest from v3 to v4, or plan a complete MSTest v3-to-v4 migration. Migrate Mstest V3 To V4 is an agent skill from runceel/ReactiveProperty. Fix build errors and breaking changes after upgrading MSTest from v3 to v4, or plan a complete MSTest v3-to-v4 migration.

When should I use Migrate Mstest V3 To V4?

Migrate Mstest V3 To V4 fits situations like: user says upgrade to MSTest v4; MSTest 4 migration; MSTest v4 breaking changes; tests dont compile after upgrading MSTest.

How do I install Migrate Mstest V3 To V4 in Claude Code?

Run `npx skills add runceel/ReactiveProperty --skill migrate-mstest-v3-to-v4 -a claude-code`. Or copy the skill folder (.agents/skills/migrate-mstest-v3-to-v4 in runceel/ReactiveProperty) into .claude/skills/migrate-mstest-v3-to-v4 in your project. Claude Code loads it when a task matches its description.

How do I install Migrate Mstest V3 To V4 in Codex?

Run `npx skills add runceel/ReactiveProperty --skill migrate-mstest-v3-to-v4 -a codex`. Or copy the skill folder (.agents/skills/migrate-mstest-v3-to-v4 in runceel/ReactiveProperty) into .agents/skills/migrate-mstest-v3-to-v4 in your project. Codex loads it when a task matches its description.

Can I use Migrate Mstest V3 To V4 in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add runceel/ReactiveProperty --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.

What does Migrate Mstest V3 To V4 need to run?

Going by SKILL.md and its folder, Migrate Mstest V3 To V4 needs the command-line tools its instructions call (dotnet).

Does Migrate Mstest V3 To V4 access the network?

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.

Is Migrate Mstest V3 To V4 safe to install?

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.

What licence does Migrate Mstest V3 To V4 use?

Migrate Mstest V3 To V4 is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Migrate Mstest V3 To V4 use?

About 6k tokens (SKILL.md is roughly 24k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Migrate Mstest V3 To V4?

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.

Who maintains Migrate Mstest V3 To V4?

runceel (a GitHub user) maintains it in runceel/ReactiveProperty, which has 944 GitHub stars. The repository holds 13 skills in this directory. The repository was last updated on August 31, 2026.

Source: runceel/ReactiveProperty on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.