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

如何正确对含SerializationInfo的自定义异常进行单元测试?

测试自定义异常的受保护序列化构造函数

要测试这个受保护的SerializationInfo+StreamingContext构造函数,核心思路是通过反射调用构造函数,模拟.NET序列化机制所需的参数环境,具体可分两种测试场景:


1. 直接测试构造函数的初始化逻辑

因为构造函数是protected的无法直接调用,所以用反射获取构造函数实例,手动填充SerializationInfo的必要字段,再验证构造出的异常属性是否符合预期:

using System;
using System.Reflection;
using System.Runtime.Serialization;
using Xunit; // 以xUnit为例,NUnit等框架写法类似

public class DatabaseVersionNotReadableExceptionTests
{
    [Fact]
    public void ProtectedSerializationConstructor_InitializesExpectedProperties()
    {
        // 获取受保护的构造函数
        var ctor = typeof(DatabaseVersionNotReadableException)
            .GetConstructor(
                BindingFlags.NonPublic | BindingFlags.Instance,
                null,
                new[] { typeof(SerializationInfo), typeof(StreamingContext) },
                null);

        // 确保构造函数存在
        Assert.NotNull(ctor);

        // 构造SerializationInfo:需填充Exception基类序列化依赖的字段
        var info = new SerializationInfo(typeof(DatabaseVersionNotReadableException), new FormatterConverter());
        // 按Exception的序列化要求添加必要属性
        info.AddValue("Message", "Database Version not found or not readable: v1.0.0");
        info.AddValue("InnerException", new InvalidOperationException("Mock inner error"));
        info.AddValue("Source", "TestAssembly");
        info.AddValue("HelpLink", "test-help-url");

        // 创建默认的StreamingContext
        var context = new StreamingContext(StreamingContextStates.All);

        // 调用构造函数实例化异常
        var exception = (DatabaseVersionNotReadableException)ctor.Invoke(new object[] { info, context });

        // 验证属性是否正确初始化
        Assert.Equal("Database Version not found or not readable: v1.0.0", exception.Message);
        Assert.IsType<InvalidOperationException>(exception.InnerException);
        Assert.Equal("Mock inner error", exception.InnerException.Message);
        Assert.Equal("TestAssembly", exception.Source);
        Assert.Equal("test-help-url", exception.HelpLink);
    }
}

2. 测试完整的序列化/反序列化流程

更贴近真实场景的测试:先序列化一个正常创建的异常,再用受保护构造函数反序列化,验证异常状态是否完整还原:

[Fact]
public void Exception_SerializesAndDeserializesWithoutLoss()
{
    // 1. 创建一个真实的异常实例
    var originalEx = new DatabaseVersionNotReadableException("v2.0.0", new ArgumentNullException("versionParam"));

    // 2. 模拟序列化过程:调用GetObjectData获取序列化信息
    var serializationInfo = new SerializationInfo(typeof(DatabaseVersionNotReadableException), new FormatterConverter());
    originalEx.GetObjectData(serializationInfo, new StreamingContext(StreamingContextStates.All));

    // 3. 通过反射调用受保护构造函数反序列化
    var ctor = typeof(DatabaseVersionNotReadableException)
        .GetConstructor(
            BindingFlags.NonPublic | BindingFlags.Instance,
            null,
            new[] { typeof(SerializationInfo), typeof(StreamingContext) },
            null);

    var deserializedEx = (DatabaseVersionNotReadableException)ctor.Invoke(new object[] { serializationInfo, new StreamingContext(StreamingContextStates.All) });

    // 4. 验证序列化前后状态一致
    Assert.Equal(originalEx.Message, deserializedEx.Message);
    Assert.IsType<ArgumentNullException>(deserializedEx.InnerException);
    Assert.Equal("versionParam", ((ArgumentNullException)deserializedEx.InnerException).ParamName);
}

关键说明:

  • SerializationInfo需要填充Exception基类序列化依赖的字段(比如Message、InnerException等),这些是.NET内置序列化机制的约定字段,缺少可能导致构造函数抛出异常。
  • StreamingContext通常传默认的StreamingContextStates.All即可,大部分场景下这个参数不会影响异常的初始化逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 16:45:42