Skip to content

Commit 52c6ae8

Browse files
Youssef1313Evangelinkgewarren
authored
Create unit-testing-mstest-migration-from-v3-to-v4.md (#47522)
* Create unit-testing-mstest-migration-from-v3-to-v4.md * Update unit-testing-mstest-migration-from-v3-to-v4.md * Update unit-testing-mstest-migration-from-v3-to-v4.md * Update unit-testing-mstest-migration-from-v3-to-v4.md * Update unit-testing-mstest-migration-from-v3-to-v4.md * Apply suggestions from code review Co-authored-by: Amaury Levé <[email protected]> * Apply suggestions from code review Co-authored-by: Genevieve Warren <[email protected]> * Rename unit-testing-mstest-migration-from-v3-to-v4.md to unit-testing-mstest-migration-v3-v4.md * Update toc.yml --------- Co-authored-by: Amaury Levé <[email protected]> Co-authored-by: Genevieve Warren <[email protected]>
1 parent e78996d commit 52c6ae8

File tree

2 files changed

+200
-0
lines changed

2 files changed

+200
-0
lines changed
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
---
2+
title: MSTest migration from v3 to v4
3+
description: Learn about migrating to MSTest v4.
4+
author: Youssef1313
5+
ms.author: ygerges
6+
ms.date: 07/22/2025
7+
---
8+
9+
# Migrate from MSTest v3 to MSTest v4
10+
11+
The preview version MSTest v4 is now available. This migration guide explores what's changed in MSTest v4 and how you can migrate to this version.
12+
13+
> [!NOTE]
14+
> Generally speaking, MSTest v4 isn't binary compatible with MSTest v3. Any library compiled against v3 must be recompiled against v4.
15+
16+
## Source breaking changes
17+
18+
These are breaking changes that might cause your test projects to fail to compile.
19+
20+
### TestMethodAttribute breaking changes
21+
22+
#### Change TestMethodAttribute.Execute to TestMethodAttribute.ExecuteAsync
23+
24+
If you implement your own `TestMethodAttribute`, you need to change the `Execute` override to be `ExecuteAsync`.
25+
This change was made to fix long-standing deadlock bugs that are caused by the synchronous blocking nature of the API.
26+
27+
For example, if you previously had the following:
28+
29+
```csharp
30+
public sealed class MyTestMethodAttribute : TestMethodAttribute
31+
{
32+
public override TestResult[] Execute(ITestMethod testMethod)
33+
{
34+
// ...
35+
return result;
36+
}
37+
}
38+
```
39+
40+
You will need to change it to the following:
41+
42+
```csharp
43+
public sealed class MyTestMethodAttribute : TestMethodAttribute
44+
{
45+
public override Task<TestResult[]> ExecuteAsync(ITestMethod testMethod)
46+
{
47+
// ...
48+
return Task.FromResult(result);
49+
}
50+
}
51+
```
52+
53+
#### TestMethodAttribute now uses caller info attributes
54+
55+
The `TestMethodAttribute` constructor has changed to have parameters that provide caller info attributes.
56+
57+
- If you inherit from `TestMethodAttribute`, you should also provide such a constructor that propagates the information to the base class.
58+
59+
```csharp
60+
public class MyTestMethodAttribute : TestMethodAttribute
61+
{
62+
public MyTestMethodAttribute([CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = -1)
63+
: base(callerFilePath, callerLineNumber)
64+
{
65+
}
66+
}
67+
```
68+
69+
- If you have attribute applications such as `[TestMethodAttribute("Custom display name")]`, switch them to `[TestMethodAttribute(DisplayName = "Custom display name")]`.
70+
71+
> [!TIP]
72+
> An analyzer with a codefix is forthcoming to help you with this migration. A single click in the IDE will fix all instances in your solution.
73+
74+
### ClassCleanupBehavior enum is removed
75+
76+
Now, the ClassCleanup methods run only at the end of the test class. Support for class cleanup to run at the end of assembly is removed.
77+
If you must run end of assembly cleanup logic, do it in `AssemblyCleanup` rather than `ClassCleanup`.
78+
The default behavior of class cleanup was previously "EndOfAssembly", which users considered to be a bug.
79+
80+
If you previously had the following code:
81+
82+
```csharp
83+
[ClassCleanup(ClassCleanupBehavior.EndOfClass)]
84+
public static void ClassCleanup(TestContext testContext)
85+
{
86+
}
87+
```
88+
89+
You will need to change it to the following:
90+
91+
```csharp
92+
[ClassCleanup]
93+
public static void ClassCleanup(TestContext testContext)
94+
{
95+
}
96+
```
97+
98+
### TestContext.Properties is now IDictionary<string, object>
99+
100+
Previously, `TestContext.Properties` was an `IDictionary`. To provide better typing, it's now `IDictionary<string, object>`.
101+
102+
If you have calls to `TestContext.Properties.Contains`, update them to `TestContext.Properties.ContainsKey`.
103+
104+
### TestTimeout enum is removed
105+
106+
This enum only had a single member, `Infinite`, whose value was `int.MaxValue`.
107+
If you had usages of `[Timeout(TestTimeout.Infinite)]`, update them to `[Timeout(int.MaxValue)]`.
108+
109+
### Types not intended for public consumption are made internal or removed
110+
111+
- `Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ObjectModel.ITestMethod` is made internal.
112+
- Note that this interface is different from ITestMethod in TestFramework assembly, which didn't change.
113+
- `Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.ObjectModel.ITestMethod` doesn't have any valid usages for users, so it was made internal.
114+
- Some of the already-obsolete types are made internal. This includes:
115+
- MSTestDiscoverer
116+
- MSTestExecutor
117+
- AssemblyResolver
118+
- LogMessageListener
119+
- TestExecutionManager
120+
- TestMethodInfo
121+
- TestResultExtensions
122+
- UnitTestOutcomeExtensions
123+
- GenericParameterHelper
124+
- Types in platform services assembly
125+
126+
### Assert APIs signature change
127+
128+
- Assert APIs that accept both `message` and `object[]` parameters now accept only `message`. Use string interpolation instead. This was a necessary change to support caller argument expression for assertion APIs.
129+
- `Assert.AreEqual` APIs for `IEquatable<T>` are removed. There are very few users of this API, and the API is misleading. Most users aren't affected by this removal, as the API didn't initially exist in MSTest v3 and was introduced in 3.2.2.
130+
- This API causes issues for F# users as well. For example, see [fsharp/fslang-suggestions/issues/905](https://github.com/fsharp/fslang-suggestions/issues/905#issuecomment-2336831360).
131+
- If you're affected, you'll get a compile error about generic type inference. All you need to do is explicitly specify the type argument as `object`.
132+
- The deprecated `Assert.ThrowsException` APIs are removed. An analyzer and codefix in MSTest 3.10 help migrate you to the newer APIs.
133+
- Usages of `Assert.IsInstanceOfType<T>(x, out var t)` should now change to `var t = Assert.IsInstanceOfType<T>(x)`.
134+
- Existing overloads that didn't have the `out` parameter changed to return the instance of type `T` instead of void. This is only a breaking change for F#.
135+
136+
### ExpectedExceptionAttribute API is removed
137+
138+
The deprecated `ExpectedExceptionAttribute` API is removed. An analyzer (MSTEST0006) and codefix in MSTest 3.2 help migrate you to `Assert.Throws`.
139+
140+
For example, if you had the following code:
141+
142+
```csharp
143+
[ExpectedException(typeof(SomeExceptionType))]
144+
[TestMethod]
145+
public void TestMethod()
146+
{
147+
MyCall();
148+
}
149+
```
150+
151+
You (or the analyzer and codefix) need to change it to the following:
152+
153+
```csharp
154+
[TestMethod]
155+
public void TestMethod()
156+
{
157+
Assert.ThrowsExactly<SomeExceptionType>(() => MyCall());
158+
}
159+
```
160+
161+
### Dropped unsupported target frameworks
162+
163+
Support for target frameworks .NET Core 3.1 to .NET 7 is dropped. The minimum supported .NET version is .NET 8.
164+
This change doesn't affect .NET Framework. .NET Framework 4.6.2 continues to be the minimum supported .NET Framework target.
165+
166+
### Unfolding strategy moved from individual data sources to TestMethodAttribute
167+
168+
Unfolding strategy is a recent feature introduced in MSTest 3.7 to work around known limitations.
169+
The property was added on individual data sources like `DataRowAttribute` and `DynamicDataAttribute`. This property has been moved to `TestMethodAttribute`.
170+
171+
### `ConditionBaseAttribute.ShouldRun` API change
172+
173+
The `ConditionBaseAttribute.ShouldRun` property was renamed to `IsConditionMet`. That makes it clearer that `ConditionMode` shouldn't be used in the implementation.
174+
175+
## Behavior breaking changes
176+
177+
These are breaking changes that might affect the behavior at run time.
178+
179+
### DisableAppDomain now defaults to true when running under Microsoft.Testing.Platform
180+
181+
In v4, and when running with Microsoft.Testing.Platform, AppDomains are disabled by default (when not specified) as the custom isolation provided is useless in most of the cases and has an important impact on performances (up to 30% slower when running under isolation).
182+
183+
However, the feature remains available. If you have scenarios requiring it, add the `DisableAppDomain` setting in runsettings.
184+
185+
### TestContext throws when used incorrectly
186+
187+
The `TestContext` type is passed to AssemblyInitialize, ClassInitialize, and to tests, but available information at each stage is different. Now, an exception is thrown when accessing a property related to a test run information as part of `AssemblyInitialize` or `ClassInitialize`.
188+
189+
- `TestContext.FullyQualifiedTestClassName` cannot be accessed in assembly initialize.
190+
- `TestContext.TestName` cannot be accessed in assembly initialize or class initialize.
191+
192+
### TestCase.Id is changing
193+
194+
To address long outstanding bugs that many users filed, the generation of `TestCase.Id` has changed. This affects Azure DevOps features, for example, tracking test failures over time.
195+
196+
### TreatDiscoveryWarningsAsErrors now defaults to true
197+
198+
v4 uses stricter defaults. As such, the default value of `TreatDiscoveryWarningsAsErrors` is now `true`. This should be a transparent change for most users and should help other users to uncover hidden bugs.

docs/navigate/devops-testing/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ items:
7373
href: ../../core/testing/unit-testing-mstest-intro.md
7474
- name: Migrate MSTest from v1 to v3
7575
href: ../../core/testing/unit-testing-mstest-migration-from-v1-to-v3.md
76+
- name: Migrate from MSTest v3 to MSTest v4
77+
href: ../../core/testing/unit-testing-mstest-migration-v3-v4.md
7678
- name: Microsoft.Testing.Platform support (MSTest runner)
7779
href: ../../core/testing/unit-testing-mstest-runner-intro.md
7880
- name: Getting started

0 commit comments

Comments
 (0)