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

如何配置FluentAssertions使用DebuggerDisplay或ToDebugString生成精简错误消息

让FluentAssertions使用DebuggerDisplay或自定义调试方法生成精简断言消息

问题场景

我有一个包含A、B、C属性的MyData类,因其他原因无法重写ToString方法,但已通过[DebuggerDisplay("{ToDebugString()}")]配置了调试显示,且类中包含ToDebugString()方法:

[DebuggerDisplay("{ToDebugString()}")]
public class MyData {
  public string A {get;set;}
  public string B {get;set;}
  public string C {get;set;}
  public string ToDebugString() => $"{A}-{B}-{C}";
}

我使用FluentAssertions对MyData对象列表做断言:

var items = new MyData[] { ... };
items.Should().Contain(i => i.A == "foo");

断言失败时,错误消息会显示完整的对象结构,内容冗长:

Expected items
{
MyProject.MyData
{
A = "a1",
B = "b1",
C = "c1"
}
} to have an item matching (i.A == "foo"). (0.2s)

虽然重写ToString可让FluentAssertions生成精简消息,但我无法修改该类。请问如何配置FluentAssertions使用ToDebugString方法,或通用使用DebuggerDisplay配置的方法来生成错误消息?


解决方案

方法1:为MyData类型注册自定义格式化器

FluentAssertions支持为特定类型注册自定义对象格式化器,直接调用目标类的ToDebugString()方法生成精简文本:

// 在测试初始化阶段注册(比如测试类的构造函数或[SetUp]方法中)
FluentAssertions.Formatting.Formatter.Add(new MyDataFormatter());

public class MyDataFormatter : IValueFormatter
{
    public bool CanHandle(Type type)
    {
        return type == typeof(MyData);
    }

    public void Format(object value, FormattedObjectGraph formattedGraph, FormattingContext context, FormatChild formatChild)
    {
        var myData = (MyData)value;
        formattedGraph.AddFragment(myData.ToDebugString());
    }
}

注册完成后,所有MyData对象在断言失败消息中都会显示ToDebugString()返回的精简内容。

方法2:通用读取DebuggerDisplay属性的格式化器

如果想复用所有类的DebuggerDisplay配置,无需为每个类型单独写格式化器,可以实现一个通用格式化器,自动解析并执行属性中配置的表达式:

// 在测试初始化阶段注册
FluentAssertions.Formatting.Formatter.Add(new DebuggerDisplayFormatter());

public class DebuggerDisplayFormatter : IValueFormatter
{
    public bool CanHandle(Type type)
    {
        return Attribute.IsDefined(type, typeof(DebuggerDisplayAttribute));
    }

    public void Format(object value, FormattedObjectGraph formattedGraph, FormattingContext context, FormatChild formatChild)
    {
        var attr = (DebuggerDisplayAttribute)Attribute.GetCustomAttribute(value.GetType(), typeof(DebuggerDisplayAttribute));
        if (attr == null) return;

        var expression = attr.Value.Trim('{', '}');
        
        // 处理调用方法的情况(如{ToDebugString()})
        if (expression.EndsWith("()"))
        {
            var methodName = expression.Substring(0, expression.Length - 2);
            var method = value.GetType().GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance);
            
            if (method != null && method.ReturnType == typeof(string))
            {
                var result = (string)method.Invoke(value, null);
                formattedGraph.AddFragment(result);
                return;
            }
        }

        // 扩展:若需要支持属性引用(如"{A}-{B}"),可通过表达式树解析表达式
        // 此处为 fallback,使用默认ToString(可选)
        formattedGraph.AddFragment(value.ToString());
    }
}

这个通用格式化器会自动识别带有DebuggerDisplayAttribute的类型,优先执行配置的方法生成精简文本,适配更多场景。


注意事项

  • 格式化器必须在断言执行前完成注册,建议放在测试项目的全局初始化代码或单个测试类的[SetUp]方法中。
  • 通用格式化器可根据需求扩展,比如支持DebuggerDisplay中的属性拼接表达式(如"{A} | {B}"),需通过表达式树解析计算表达式值。

内容的提问来源于stack exchange,提问作者Gaspar Nagy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 16:33:21