使用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
相关产品推荐
相关产品推荐

