You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用DynamicData特性传递复杂类型时,Test Explorer缺失测试子条目

如何让Visual Studio Test Explorer为自定义/复杂类型的DynamicData测试生成子条目?

问题背景

当使用[DynamicData]特性提供int等原始类型的枚举值时,Visual Studio Test Explorer会为每个动态数据值生成独立的测试子条目:

原始类型测试代码示例

public static IEnumerable<object[]> PrimitiveTestData
{
    get
    {
        yield return new object[] {1};
        yield return new object[] {2};
        yield return new object[] {3};
    }
}

[TestMethod]
[DynamicData(nameof(PrimitiveTestData))]
public void TestWithPrimitiveTestData(int value)
{
    Console.WriteLine($"value is {value}");
}

此时测试资源管理器会生成3个对应每个动态数据的子条目(左侧带有展开三角图标),可单独选中进行调试。

但当传递自定义/复杂类型(比如自定义record)时,Test Explorer不会生成这些独立子条目:

复杂类型测试代码示例

public record CustomRecord(
    decimal Number, 
    string Comment
);

public static IEnumerable<object[]> RecordTestData
{
    get
    {
        yield return new object[] {
            new CustomRecord(1m, "first")
        };

        yield return new object[] {
            new CustomRecord(2m, "second")
        };

        yield return new object[] {
            new CustomRecord(3m, "third")
        };
    }
}

[TestMethod]
[DynamicData(nameof(RecordTestData))]
public void TestWithRecordTestData(CustomRecord item)
{
    Console.WriteLine($"item number is {item.Number} entries");
}

这种情况下测试资源管理器中没有展开三角图标,所有动态数据对应的测试实例合并为一个条目,无法单独调试单个数据对应的测试。

解决方案

核心原因是Test Explorer无法自动为复杂类型生成唯一可识别的测试标识,需要手动为每个动态数据条目指定显示名称,让Test Explorer能区分不同的测试实例。以下是两种可行方案:

方式1:重写自定义类型的ToString()方法

Test Explorer会使用类型的ToString()返回值作为子条目的标识,重写后即可生成独立条目:

public record CustomRecord(
    decimal Number, 
    string Comment
)
{
    // 重写ToString,返回唯一可识别的字符串
    public override string ToString()
    {
        return $"Number: {Number}, Comment: {Comment}";
    }
}

重新生成解决方案后,Test Explorer会自动为每个CustomRecord实例生成对应的子条目,显示内容为ToString()返回的字符串。

方式2:使用DynamicData特性的DisplayNameGenerator参数

如果不想修改自定义类型的代码,可以指定自定义的显示名称生成器,这种方式更灵活:

首先定义一个实现IDataDisplayNameGenerator的类:

public class CustomRecordDisplayNameGenerator : IDataDisplayNameGenerator
{
    public string GetDisplayName(MethodInfo methodInfo, object[] data)
    {
        if (data[0] is CustomRecord record)
        {
            return $"Test with {record.Number} - {record.Comment}";
        }
        // 回退到默认名称生成逻辑
        return DataDisplayNameGenerator.Default.GetDisplayName(methodInfo, data);
    }
}

然后在测试方法的DynamicData特性中指定该生成器:

[TestMethod]
[DynamicData(nameof(RecordTestData), DisplayNameGenerator = typeof(CustomRecordDisplayNameGenerator))]
public void TestWithRecordTestData(CustomRecord item)
{
    Console.WriteLine($"item number is {item.Number} entries");
}

效果验证

采用上述任意一种方式后,Test Explorer都会为每个动态数据实例生成独立的子条目,你可以右键单个条目选择调试,满足单独调试单个测试实例的需求。


内容的提问来源于stack exchange,提问作者me.at.coding

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 14:30:07