尧图精选

MSTest v3 升级到 v4 完全迁移指南:源码破坏性变更、行为变更与 MSTest.Sdk/MTP 兼容性实战(基于 dotnet-test-migration 插件)

🕒 发布时间:2026/9/18 21:14:58 📁 来源:尧图网络
MSTest v3 升级到 v4 完全迁移指南源码破坏性变更、行为变更与 MSTest.Sdk/MTP 兼容性实战基于 dotnet-test-migration 插件【免费下载链接】skillsRepository for skills to assist AI coding agents with .NET and C#项目地址: https://gitcode.com/GitHub_Trending/skills17/skills本文是 dotnet-test-migration 插件中migrate-mstest-v3-to-v4技能SKILL.md的深度实战解读。它面向把测试项目从 MSTest v3 升级到 v4 的 .NET 开发者覆盖从包升级、编译错误修复、运行时行为差异到 CI 测试发现异常的完整迁移路径。读完本文你将掌握 MSTest v4 的全部源码级破坏性变更Execute→ExecuteAsync、CallerInfo 构造函数、ExpectedException 移除、Assert API 重命名等与行为级变更TestCase.Id、AppDomain、TreatDiscoveryWarningsAsErrors 默认值等并能在 MSTest.Sdk Microsoft.Testing.PlatformMTP场景下修复vstest.console突然无法发现测试的经典问题。一、迁移概览为什么 v4 不能当作小版本处理MSTest v4与 MSTest v3 不是二进制兼容的——任何针对 v3 编译的库都必须针对 v4 重新编译。这意味着升级不是简单地替换 NuGet 包版本而是一次需要包更新 源码修复 行为核对三个层面的完整工程。迁移的成功标准是使用 MSTest v4 的项目干净编译、测试全部通过并且所有源码不兼容与行为变更都已被纳入考量。特别要注意一次干净编译并不能排除迁移失败——测试发现失败discovery failures、TestContext生命周期异常和测试历史变化都属于运行时的迁移失败这正是本技能强调First Action必须实际检查项目而非凭记忆作答的原因。在 dotnet-test-migration 插件的技能矩阵中migrate-mstest-v3-to-v4负责 v3→v4 这一步而它明确要求 v1/v2 的项目先走migrate-mstest-v1v2-to-v3SKILL.md再回到这里形成 v1 → v3 → v4 的完整升级链路。何时使用 / 何时不使用使用场景升级MSTest.TestFramework、MSTest.TestAdapter或MSTest元包从 3.x 到 4.x升级MSTest.Sdk从 3.x 到 4.x修复更新到 MSTest v4 包之后出现的编译错误解决升级后测试执行的行为差异运行时报错、发现失败、历史丢失为 v4 更新自定义TestMethodAttribute或ConditionBaseAttribute实现。不使用场景避免误触发项目已经使用 MSTest v4 且编译干净——迁移已完成项目还在 MSTest v1 或 v2——必须先走 v1v2→v3 技能再回到这里项目根本没有使用 MSTest要做框架间迁移如 MSTest 转到 xUnit 或 NUnit。技能输入与结果决策技能输入是可选的项目/解决方案路径.csproj、.sln或.slnx应自行在工作目录中 glob 发现仅当找不到或确实有歧义时才询问用户、构建命令如dotnet build可自动检测、测试命令如dotnet test可自动检测。技能还定义了一组改变结果走向的决策表关键条目包括检测到的请求或状态必需动作工作区中提供了文件在该处搜索并打开返回的字面路径技能目录不是项目目录某个工具拒绝合法路径时换其他读取/编辑工具重试不要为可自行发现的路径去问用户用户要求对提供的文件应用修改修复我的项目/文件、请更新这些源码、做出修改、然后构建并运行编辑每一处受影响位置针对实际包版本运行最窄范围且有意义的构建/测试命令技能被激活不是只停留在给建议的理由用户询问我该预期什么怎么修复这些变更或寻求兼容性建议、计划即使源码可见也要基于实际项目状态直接回答单一症状的回答保持聚焦只纳入会改变决策的相邻风险完整迁移但 TFM 不受支持先更新 TFM再更新 MSTest 包然后修复源码破坏——不要把顺序埋在一堆发布说明清单里自定义TestMethodAttribute子类把ExecuteAsync、CallerInfo 传播、显示名处理、子类的重试/结果语义当作一个耦合的迁移整体修复真实的类而非占位示例MSTest.Sdkv4 的源码/API 错误ManagedType、TestTimeout、Contains给出精确的源码替换方案然后补充相邻的运行器警告MTP 模式不再提供Microsoft.NET.Test.Sdk仅在仍需 VSTest 发现时才添加它MSTest.Sdkv4 搭配vstest.console这是 v4 变更MTP 模式不再带入Microsoft.NET.Test.Sdk。要么保留 MTP 并添加该包以支持过渡期 VSTest 发现要么选择UseVSTest要么把 CI 迁到dotnet test并说明该选择保留了哪种运行器响应准则对 Agent 的硬性要求先识别当前版本推荐任何迁移步骤前明确说出项目中检测到的 MSTest 版本例如你的项目使用 MSTest v3 (3.8.0)这确认你已经读过项目文件解析而不是臆测目标版本用户要最新时查询项目配置的包源选择执行时最新的稳定 MSTest v4 版本绝不未经核实就照抄技能里的示例版本所有 MSTest 包保持同一解析版本聚焦修复请求只处理第 3 步中相关的破坏性变更怎么修仍是回答请求而非编辑请求始终用用户实际的类型与方法名给出具体的修复代码夹具仍引用 v3 时不要声称绿色 v3 构建能验证 v4 兼容性该预期什么类问题呈现第 3 步速查表中全部主要破坏性变更每项给一行修复摘要并提及第 4 步的关键行为变更尤其 TestCase.Id 历史影响与 TreatDiscoveryWarningsAsErrors 默认值行为/运行时症状报告把症状匹配到第 4 步行为变更表给出针对症状的建议并提醒其他值得关注的变更CI/测试发现问题聚焦 4.5MSTest.Sdk v4 在默认 MTP 模式下不再包含 Microsoft.NET.Test.Sdk——vstest.console仍需要它和 4.4TreatDiscoveryWarningsAsErrors说明根因并给出全部三条出路结果证明实现工作收尾时报告检测到的 v3 版本、解析出的 v4 版本、运行器选择、改动的文件、真实的构建/测试计数。绝不允许靠推断汇报构建、VSTest 兼容性、发现或测试通过。二、完整迁移工作流Step 1–5提交策略除非用户要求不要创建提交。保持包、源码和行为变更在 diff 中逻辑可分但必须完成并验证所请求的迁移。Step 1评估项目现状通过在.csproj、Directory.Build.props或Directory.Packages.props中检查MSTest、MSTest.TestFramework、MSTest.TestAdapter或MSTest.Sdk的包引用识别当前 MSTest 版本确认项目在 MSTest v33.x。如果在 v1 或 v2先用migrate-mstest-v1v2-to-v3检查目标框架——MSTest v4 放弃了对 .NET Core 3.1 到 .NET 7 的支持。受支持的目标框架为net8.0、net9.0、net462.NET Framework 4.6.2、uap10.0.16299UWP、net9.0-windows10.0.17763.0现代 UWP、net8.0-windows10.0.18362.0WinUI检查自定义TestMethodAttribute子类——v4 中这些需要变更检查ExpectedExceptionAttribute的使用——v4 中已移除自 v3 起被分析器 MSTEST0006 标记为弃用检查Assert.ThrowsException已弃用的使用——v4 中已移除运行一次干净构建建立现有错误/警告的基线。这一步在仓库评估夹具中有大量对应的真实场景例如 v3-custom-testmethod 里有一个覆盖Execute的RetryTestMethodAttributev3-expected-exception 里有多个[ExpectedException]注解方法v3-assert-changes 里同时出现Assert.ThrowsException、[Timeout(TestTimeout.Infinite)]与[ClassCleanup(ClassCleanupBehavior.EndOfClass)]——真实迁移中这些破坏性变更常常共存于同一项目。Step 2更新包到 MSTest v4先从配置的包源解析最新的稳定 v4 版本然后在元包、独立包、MSTest.Sdk与中央包管理Central Package Management中统一锁定该精确版本MSTest元包把PackageReference更新为解析出的精确版本独立包MSTest.TestFramework与MSTest.TestAdapter更新到同一版本MSTest.Sdk更新项目或global.json中的 SDK 版本钉扎到同一版本。然后运行dotnet restore与dotnet build收集所有错误供 Step 3 使用。仓库的评估夹具中展示了典型的 v4 包形态例如 v3-sdk-project 使用Project SdkMSTest.Sdk/4.1.0的 SDK 风格项目而验证夹具v3-verified-migration则以file-contains断言要求PackageReference IncludeMSTest.TestFramework Version4.与PackageReference IncludeMSTest.TestAdapter Version4.确保包引用真的被升到 4.x。Step 3解决源码级破坏性变更速查表系统地遍历编译错误用下面的速查表识别所有适用的变更并逐一修复。重要提示在开始修复前先扫描整个项目的全部下述模式——多个破坏性变更常常同时存在于同一个项目完整迁移评估夹具 中的 Full MSTest v3 to v4 migration with multiple breaking changes 场景正是同时覆盖 TFM、ExecuteAsync、ExpectedException、ClassCleanupBehavior、格式化字符串、Contains、TestTimeout 七个变更的典型样例错误 / 代码模式破坏性变更修复自定义TestMethodAttribute重写ExecuteExecute 被移除改为返回TaskTestResult[]的ExecuteAsync3.1[TestMethod(name)]或自定义属性构造函数新增 CallerInfo 参数用命名参数DisplayName name子类传播 CallerInfo3.2ClassCleanupBehavior.EndOfClass枚举被移除去掉参数只用[ClassCleanup]3.3TestContext.Properties.Contains(key)Properties变为IDictionarystring, object改为ContainsKey(key)3.4[Timeout(TestTimeout.Infinite)]TestTimeout枚举被移除替换为[Timeout(int.MaxValue)]3.5TestContext.ManagedType属性被移除使用FullyQualifiedTestClassName3.6Assert.AreEqual(a, b, msg {0}, arg)消息params 重载被移除使用字符串插值$msg {arg}3.7Assert.ThrowsExceptionT(...)被重命名替换为Assert.ThrowsExactlyT(...)或Assert.ThrowsT(...)3.7Assert.IsInstanceOfTypeT(obj, out var t)out 参数被移除使用var t Assert.IsInstanceOfTypeT(obj)3.7[ExpectedException(typeof(T))]属性被移除把断言移入测试体Assert.ThrowsExactlyT(() ...)3.8项目目标是 net5.0、net6.0 或 net7.0TFM 被丢弃改为 net8.0 或 net9.03.93.1 TestMethodAttribute.Execute → ExecuteAsync自定义TestMethodAttribute子类若重写了Execute要改为ExecuteAsync。这一变更的动机是v3 的同步ExecuteAPI 在测试代码内部使用async/await时会造成死锁——同步包装器阻塞线程而异步操作恰恰需要同一个线程才能完成。// 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 TaskTestResult[] 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 TaskTestResult[] ExecuteAsync(ITestMethod testMethod) { // custom async logic return await base.ExecuteAsync(testMethod); } }当覆盖逻辑纯粹是同步的使用Task.FromResult当要调用base.ExecuteAsync或其他异步方法时使用async/await。仓库的真实夹具 v3-custom-testmethod 展示了一个带重试计数、调用base.Execute(testMethod)并检查UnitTestOutcome.Passed的RetryTestMethodAttribute——迁移后这段循环逻辑应放进ExecuteAsync同步分支用Task.FromResult包装评估要求输出中出现ExecuteAsync与TaskTestResult[]签名并点明该变更修复了 v3 同步 API 的死锁缺陷。3.2 TestMethodAttribute 的 CallerInfo 构造函数TestMethodAttribute的构造函数现在带有[CallerFilePath]与[CallerLineNumber]参数。如果继承自 TestMethodAttribute把 caller info 传播给基类public class MyTestMethodAttribute : TestMethodAttribute { public MyTestMethodAttribute( [CallerFilePath] string callerFilePath , [CallerLineNumber] int callerLineNumber -1) : base(callerFilePath, callerLineNumber) { } }如果子类有自己的显示名构造函数不要把该字符串传给 v4 基类构造函数——只传播 caller info 并赋值DisplayName属性public sealed class NamedTestMethodAttribute : TestMethodAttribute { public NamedTestMethodAttribute( string displayName, [CallerFilePath] string callerFilePath , [CallerLineNumber] int callerLineNumber -1) : base(callerFilePath, callerLineNumber) { DisplayName displayName; } }如果使用[TestMethodAttribute(Custom display name)]改用命名参数语法// Before (v3) [TestMethodAttribute(Custom display name)] // After (v4) [TestMethodAttribute(DisplayName Custom display name)]仓库的 CallerInfo 构造函数夹具 给出了一个带string category构造参数的CategorizedTestMethodAttribute以及[TestMethod(My custom display name)]的用法——两者在 v4 下都必须按上述模式改造评估同时覆盖CallerFilePath/CallerLineNumber传播与DisplayName命名参数两种要求。3.3 ClassCleanupBehavior 枚举移除ClassCleanupBehavior枚举被移除。v3 中它控制类清理是在类结束时EndOfClass还是程序集结束时EndOfAssembly执行v4 中类清理总是在类结束时运行。去掉枚举参数即可// Before (v3) [ClassCleanup(ClassCleanupBehavior.EndOfClass)] public static void ClassCleanup(TestContext testContext) { } // After (v4) [ClassCleanup] public static void ClassCleanup(TestContext testContext) { }如果之前使用ClassCleanupBehavior.EndOfAssembly请把该清理逻辑移到[AssemblyCleanup]方法中。3.4 TestContext.Properties 类型变更TestContext.Properties从IDictionary变为IDictionarystring, object。把所有Contains调用更新为ContainsKey// Before (v3) testContext.Properties.Contains(key); // After (v4) testContext.Properties.ContainsKey(key);3.5 TestTimeout 枚举移除TestTimeout枚举只有TestTimeout.Infinite一个成员被移除替换为int.MaxValue// Before (v3) [Timeout(TestTimeout.Infinite)] // After (v4) [Timeout(int.MaxValue)]3.6 TestContext.ManagedType 移除TestContext.ManagedType属性被移除改用TestContext.FullyQualifiedTestClassName。在 v3-sdk-project 的评估场景中ManagedType、TestTimeout.Infinite与Properties.Contains三个错误在同一个 MSTest.Sdk 项目里一起出现需要一并替换。3.7 Assert API 签名变更消息 params 参数移除原本同时接受message与object[]参数的 Assert 方法现在只接受message。用字符串插值替代格式字符串// 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 重命名Assert.ThrowsException系列 API 被重命名。用Assert.ThrowsExactly严格类型匹配或Assert.Throws接受派生异常类型// Before (v3) Assert.ThrowsExceptionInvalidOperationException(() DoSomething()); // After (v4) -- exact type match (same behavior as old ThrowsException) Assert.ThrowsExactlyInvalidOperationException(() DoSomething()); // After (v4) -- also catches derived exception types Assert.ThrowsInvalidOperationException(() DoSomething());Assert.IsInstanceOfType out 参数变更Assert.IsInstanceOfTypeT(x, out var t)变为var t Assert.IsInstanceOfTypeT(x)// Before (v3) Assert.IsInstanceOfTypeMyType(obj, out var typed); // After (v4) var typed Assert.IsInstanceOfTypeMyType(obj);对该赋值重写要应用到每一处出现保留断言的具体类型与后续对 typed 变量的所有使用。当源码可用时展示或编辑真实方法而非替换成泛化的MyType示例然后验证项目可编译。这一场景对应的编译错误是CS1615: Argument 2 should not be passed with the out keyword评估夹具 v3-instanceoftype 要求把 typed 变量改为从返回值赋值。IEquatableT 的 Assert.AreEqual 移除若出现泛型类型推断错误把类型参数显式指定为object。3.8 ExpectedExceptionAttribute 移除[ExpectedException]属性在 v4 中被彻底移除。MSTest 3.2 引入了MSTEST0006分析器来标记[ExpectedException]用法并建议迁移到Assert.ThrowsExactly这在 v3 上是非破坏性变更v4 中属性直接消失。迁移到Assert.ThrowsExactly// Before (v3) [ExpectedException(typeof(InvalidOperationException))] [TestMethod] public void TestMethod() { MyCall(); } // After (v4) [TestMethod] public void TestMethod() { Assert.ThrowsExactlyInvalidOperationException(() MyCall()); }当测试在抛出调用之前有设置代码时只把抛出调用包进 lambda——保持 Arrange/Act 分离清晰// 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.ThrowsExactlyArgumentNullException(() service.Validate(null)); }对异步测试方法使用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.ThrowsExactlyAsyncHttpRequestException( () client.GetAsync(https://localhost:0)); }如果[ExpectedException]使用了AllowDerivedTypes属性改用Assert.ThrowsAsyncT基类型匹配而非Assert.ThrowsExactlyAsyncT精确类型匹配。聚焦迁移时转换提供的源码中每个被注解的方法只把预期抛出的语句包进 lambda把 arrange/setup 语句留在 lambda 之外然后运行受影响的测试。仓库的 ValidationServiceTests 夹具 里两个[ExpectedException]方法ArgumentNullException与InvalidOperationException正是没有前置代码的简单场景评估还要求提到 MSTEST0006 分析器本可以在 v3 阶段就捕获该问题。3.9 被丢弃的目标框架MSTest v4 支持.NET 8 及更高与.NET Framework 4.6.2 及更高。平台相关的受支持目标还包括uap10.0.16299UWP现代 UWP 与 WinUI 使用其对应的 Windows 特定 .NET TFM。.NET Core 3.1 到 .NET 7 被丢弃。如果测试项目面向不受支持的框架更新TargetFramework!-- Before -- TargetFrameworknet6.0/TargetFramework !-- After -- TargetFrameworknet8.0/TargetFramework评估要求明确MSTest v4 丢弃了 .NET 6.0以及 .NET 7.0、.NET Core 3.1 到 .NET 5推荐 net8.0 作为最低 .NET 版本同时 .NET Framework 4.6.2 继续受支持绝不建议留在 net6.0 上使用 MSTest v4。3.10 展开策略UnfoldingStrategy移动到 TestMethodAttributeUnfoldingStrategy属性MSTest 3.7 引入从各个数据源属性DataRowAttribute、DynamicDataAttribute移动到了TestMethodAttribute上。3.11 ConditionBaseAttribute.ShouldRun 重命名ConditionBaseAttribute.ShouldRun属性被重命名为IsConditionMet。3.12 变为 internal 或被移除的类型以下原本 public 的类型现在变为 internal 或被移除MSTestDiscoverer、MSTestExecutor、AssemblyResolver、LogMessageListenerTestExecutionManager、TestMethodInfo、TestResultExtensionsUnitTestOutcomeExtensions、GenericParameterHelperPlatformServices 程序集中的ITestMethodTestFramework 中的那个未变如果代码引用了其中任何类型需要寻找替代方案或移除依赖。Step 4处理行为级变更不产生编译错误这些变更不会导致构建失败但会改变测试运行期行为症状原因修复Azure DevOps 中测试显示为新、测试历史丢失TestCase.Id生成算法变更4.3无需代码修复历史会重新建立基线TestContext.TestName在[ClassInitialize]中抛异常v4 强制执行生命周期作用域4.2把访问移到[TestInitialize]或测试方法中测试未被发现 / 发现失败TreatDiscoveryWarningsAsErrors现在为 true4.4修复警告或在 .runsettings 中设为 false之前不挂的测试现在挂起默认禁用 AppDomain4.1在 .runsettings 的RunConfiguration中把DisableAppDomain设为 falseMSTest.Sdk 项目升级 v4 后 vstest.console 找不到测试MSTest.Sdk 默认 MTPv4 在 MTP 模式下不再添加Microsoft.NET.Test.Sdk4.5保留 MTP 并显式添加包、设置UseVSTest或把 CI 切到dotnet test分析器出现新警告分析器严重级别升级4.6修复警告或在 .editorconfig 中抑制4.1 DisableAppDomain 默认变为 trueAppDomain 默认被禁用。在 .NET Framework 上当运行于 testhost 内部dotnet test和 VS 的默认方式时MSTest 会自动重新启用 AppDomain。如需显式控制 AppDomain 隔离通过.runsettings设置RunSettings RunConfiguration DisableAppDomainfalse/DisableAppDomain /RunConfiguration /RunSettings4.2 错误使用 TestContext 时会抛异常MSTest v4 现在会在错误生命周期阶段访问测试特定属性时抛异常TestContext.FullyQualifiedTestClassName—— 不能在[AssemblyInitialize]中访问TestContext.TestName—— 不能在[AssemblyInitialize]或[ClassInitialize]中访问。修复把对TestContext.TestName的访问从[ClassInitialize]移到[TestInitialize]或单个测试方法中那里才有每测试上下文。不要用FullyQualifiedTestClassName替换TestName作为变通——两者的语义不同。评估场景 understand-behavioral-changes 正是这个症状与 4.3 的组合。4.3 TestCase.Id 生成算法变更TestCase.Id的生成算法已变更以修复长期存在的缺陷。这可能影响 Azure DevOps 的测试结果跟踪例如随时间变化的失败跟踪。无需代码修复但要意识到测试结果历史会出现断层——升级后测试会被视为全新测试历史会重新建立基线。4.4 TreatDiscoveryWarningsAsErrors 默认变为 truev4 使用更严格的默认值。发现警告现在被视为错误这意味着之前虽有发现问题但照常运行的测试现在可能整体失败。升级后若看到意外的测试失败不是构建错误而是测试未发现检查发现警告。要恢复 v3 行为以便排查RunSettings MSTest TreatDiscoveryWarningsAsErrorsfalse/TreatDiscoveryWarningsAsErrors /MSTest /RunSettings建议修复底层的发现警告而不是抑制该设置。4.5 MSTest.Sdk 与 vstest.console 的兼容性MSTest.Sdk 默认使用 Microsoft.Testing.PlatformMTP模式。MSTest.Sdk v3 在该模式下仍会添加Microsoft.NET.Test.Sdkv4 移除了这个不必要的引用。因此一个单独调用vstest.console的 CI 管道在 v4 升级后可能立刻掉到发现 0 个测试。这是 v4 的行为级破坏性变更之一不要声称该行为在 v4 之前就存在。方案 A —— 保留 MTP 并支持过渡期 VSTest 发现显式添加精确兼容版本的Microsoft.NET.Test.Sdk包。当 MTP 仍是主运行器、但现有vstest.console任务暂时无法移除时这是破坏性最小的修复。使用直接PackageReference版本为从配置源解析出的精确兼容版本在中央包管理下在Directory.Packages.props中添加或更新Microsoft.NET.Test.Sdk的PackageVersion并保持项目引用无版本号。不要照抄固定的示例版本。用实际的vstest.console命令验证——一次通过的dotnet testMTP 运行并不能证明 VSTest 发现正常。方案 B —— 把项目切换到 VSTest 模式设置UseVSTest属性MSTest.Sdk 就会添加Microsoft.NET.Test.SdkPropertyGroup UseVSTesttrue/UseVSTest /PropertyGroup保留 Step 2 解析出的精确MSTest.Sdkv4 钉扎版本该选项只改运行器不改选定的 MSTest 版本或目标框架。方案 C —— 把 CI 切换到dotnet test把 CI 管道中的vstest.console调用替换为dotnet test。它与 MTP 原生兼容是 MSTest.Sdk 项目的推荐长期方案。仓库的评估场景 handle-mstest-sdk-and-mtp-changes-in-v4 正是MSTest.Sdk/4.1.0 MTP CI 跑 vstest.console 找不到测试的复现评估要求解释v4 不再在 MTP 模式下添加 Microsoft.NET.Test.Sdk并给出添加显式 PackageReference 或迁移 CI 到dotnet test两种路径。4.6 分析器严重级别变更多个分析器默认从 Info 升级为 WarningMSTEST0001、MSTEST0007、MSTEST0017、MSTEST0023、MSTEST0024、MSTEST0025MSTEST0030、MSTEST0031、MSTEST0032、MSTEST0035、MSTEST0037、MSTEST0045审查并修复任何新警告若是有意为之可在.editorconfig中抑制。Step 5验证运行dotnet build—— 确认零错误并审查任何新警告运行dotnet test—— 确认所有测试通过把测试结果通过/失败计数与迁移前基线对比如果使用 Azure DevOps 测试跟踪注意TestCase.Id变更可能影响历史连续性检查是否有测试因更严格的发现规则被静默丢弃。三、验收清单与常见陷阱Validation 清单所有 MSTest 包更新到 4.x项目零错误构建dotnet test下所有测试通过自定义TestMethodAttribute子类已为ExecuteAsync与 CallerInfo 更新ExpectedExceptionAttribute已替换为Assert.ThrowsExactlyAssert.ThrowsException已替换为Assert.ThrowsExactly或Assert.ThrowsClassCleanupBehavior枚举用法已移除TestContext.Properties.Contains已更新为ContainsKey所有目标框架为 net8.0、net9.0、net462、uap10.0.16299 或 WinUI行为级变更已审查并处理迁移期间没有测试丢失对比测试计数常见陷阱速查陷阱解决方案自定义TestMethodAttribute仍重写Execute改为返回TaskTestResult[]的ExecuteAsyncTestMethodAttribute(display name)不再编译使用TestMethodAttribute(DisplayName display name)找不到ClassCleanupBehavior枚举去掉枚举参数[ClassCleanup]现在总在类结束时运行。需要程序集结束清理时用[AssemblyCleanup]TestContext.Properties.Contains缺失用ContainsKey——Properties现在是IDictionarystring, object找不到ExpectedException属性在测试体内替换为Assert.ThrowsExactlyT(() ...)找不到Assert.ThrowsException替换为Assert.ThrowsExactly派生类型用Assert.Throws带格式字符串参数的Assert.AreEqual失败用字符串插值$message {value}之前不挂的测试现在挂起AppDomain 默认禁用.NET Framework 在 testhost 中会自动重新启用Azure DevOps 测试历史中断符合预期 ——TestCase.Id生成算法变更无代码修复结果会重新建立基线发现警告现在导致运行失败TreatDiscoveryWarningsAsErrors默认 true修复发现警告net6.0/net7.0 目标不编译更新到 net8.0 —— MSTest v4 支持 net8.0、net9.0、net462、uap10.0.16299、现代 UWP 和 WinUI四、在仓库中的配套资源技能本体migrate-mstest-v3-to-v4/SKILL.md本文的权威来源含 frontmatter 触发条件ExecuteAsync、CallerInfo、DisplayName、ClassCleanupBehavior、ContainsKey、ThrowsExactly/ExpectedException、TestTimeout.Infinite、ManagedType、TestCase.Id、TreatDiscoveryWarningsAsErrors等均为 v4 相关触发词测试夹具tests/dotnet-test-migration/migrate-mstest-v3-to-v4/fixtures/14 个覆盖各破坏性变更的真实项目从v3-custom-testmethod到v3-verified-migration评估定义eval.yaml11 个评估场景及其 grader/rubric可当作验收标准清单阅读插件总览dotnet-test-migration/README.md技能矩阵与test-migration编排 Agent 说明。迁移完成后建议结合dotnet-test插件中的 writing-mstest-tests现代 MSTest v4 断言 API 与测试编写最佳实践与 run-tests迁移后的测试运行与验证继续深化MSTest v1/v2 的老项目则应先阅读 migrate-mstest-v1v2-to-v3。【免费下载链接】skillsRepository for skills to assist AI coding agents with .NET and C#项目地址: https://gitcode.com/GitHub_Trending/skills17/skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →