testfx icon indicating copy to clipboard operation
testfx copied to clipboard

MSTest 4.x breaking change causes TestContext.Properties to throw KeyNotFoundException instead of returning null

Open timmydo opened this issue 1 month ago • 2 comments

Describe the bug

During our migration from MSTest 3.x to 4.x, I've noticed a breaking change where calls to TextContext.Properties["NonExistent"] throw an exception instead of returning null. We have a lot of code that depends on this returning null.

Steps To Reproduce

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <IsPackable>false</IsPackable>
    <IsTestProject>true</IsTestProject>
    <EnableMSTestRunner>true</EnableMSTestRunner>
    <OutputType>Exe</OutputType>
    
    <!-- Set MSTestVersion property to switch versions: 3 or 4 (default) -->
    <MSTestVersion Condition="'$(MSTestVersion)' == ''">4</MSTestVersion>
  </PropertyGroup>

  <!-- MSTest 3.x -->
  <ItemGroup Condition="'$(MSTestVersion)' == '3'">
    <PackageReference Include="MSTest" Version="3.6.3" />
  </ItemGroup>

  <!-- MSTest 4.x (default) -->
  <ItemGroup Condition="'$(MSTestVersion)' == '4'">
    <PackageReference Include="MSTest" Version="4.0.2" />
  </ItemGroup>

</Project>
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MSTestPropertyRepro;

[TestClass]
public class PropertyAccessTests
{
    public TestContext? TestContext { get; set; }

    [TestMethod]
    public void TestAccessingNonExistentProperty()
    {
        // Try to access a property that doesn't exist
        try
        {
            var nonExistent = TestContext?.Properties["NonExistentProperty"];
            Console.WriteLine($"NonExistentProperty returned: {nonExistent ?? "null"}");
            
            if (nonExistent == null)
            {
                Console.WriteLine("✓ MSTest 3.x behavior: Returns null for missing properties");
            }
            else
            {
                Console.WriteLine($"✗ Unexpected: Got value '{nonExistent}'");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"✗ MSTest 4.x behavior: Throws exception for missing properties");
            Console.WriteLine($"Exception: {ex.GetType().Name} - {ex.Message}");
            throw;
        }
    }
}

MSTest 3.x

MSTest v3.6.3 (UTC 11/11/2024) [win-x64 - .NET 10.0.0]

Test run summary: Passed! - bin\Debug\net10.0\MSTestPropertyRepro.dll (net10.0|x64)
  total: 1
  failed: 0
  succeeded: 1
  skipped: 0

✅ Returns null when accessing non-existent properties - Test PASSES

MSTest 4.x

MSTest v4.0.0-preview.25358.7 (UTC 7/8/2025) [win-x64 - .NET 10.0.0]

Test run summary: Failed! - bin\Debug\net10.0\MSTestPropertyRepro.dll (net10.0|x64)
  total: 1
  failed: 1
  succeeded: 0
  skipped: 0
  
Exception: System.Collections.Generic.KeyNotFoundException: 
The given key 'NonExistentProperty' was not present in the dictionary.

❌ Throws KeyNotFoundException when accessing non-existent properties - Test FAILS

Breaking Change

// MSTest 3.x
var value = TestContext.Properties["NonExistent"]; // Returns null

// MSTest 4.x
var value = TestContext.Properties["NonExistent"]; // Throws KeyNotFoundException

timmydo avatar Nov 18 '25 17:11 timmydo

According to the Migrate from MSTest v3 to v4 document that was published when MSTest v4 was released, the Properties dictionary is now an IDictionary<string, object>. So you can either leverage calls to TestContextPoerties.ContainsKey("NonExistent") or use TryGetValue:

var contextValue = TestContext.Properties.TryGetValue("NonExistent", out var pValue) ? pValue?.ToString() : null;

shepherdm3 avatar Dec 11 '25 00:12 shepherdm3

Sorry for the inconvenience. This is a documented change, that was postponed till major version upgrade because it is breaking.

Added this specific case to the migration guide: https://github.com/dotnet/docs/pull/50543

nohwnd avatar Dec 11 '25 10:12 nohwnd