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

如何使用NSubstitute对结构化日志调用进行单元测试?

问题描述

原日志代码:

_logger.LogError(exception, $"Encountered {exception.GetType().Name}. Unable to verify user with id {user.UserId}");

对应的单元测试断言原本可正常运行:

var logger = Substitute.For<ILogger<SyncService>>();

// 其他Arrange、Act、Assert步骤

logger.Received(1).LogError(exception, "Encountered NullReferenceException. Unable to verify user with id 1");

因需求改为结构化日志后,日志代码更新为:

_logger.LogError(exception, "Encountered {exceptionType}. Unable to verify user with id {userId}", exception.GetType().Name, user.UserId);

修改断言后测试失败,报错显示内部在比较string实例与FormattedLogValues实例,但FormattedLogValues已不再对外公开。已知Moq有It.IsAnyType方法可忽略消息模板类型,询问NSubstitute是否有类似方案。

解决方案

NSubstitute提供两种可行方案处理该问题:

1. 匹配任意类型绕过类型校验

使用Arg.Any<object>()匹配消息模板参数,无需关心内部的FormattedLogValues类型,直接校验结构化参数即可:

logger.Received(1).LogError(
    exception,
    Arg.Any<object>(),
    Arg.Is<string>(x => x == "NullReferenceException"),
    Arg.Is<int>(x => x == 1)
);

2. 精确验证消息模板与参数

如果需要同时验证消息模板的正确性,可直接传入模板字符串,搭配参数匹配校验结构化参数:

logger.Received(1).LogError(
    exception,
    "Encountered {exceptionType}. Unable to verify user with id {userId}",
    Arg.Is<string>(x => x == exception.GetType().Name),
    Arg.Is<int>(x => x == user.UserId)
);

这种方式更严谨,既保证消息模板符合预期,也能验证结构化参数的准确性,NSubstitute会自动处理内部的类型包装,无需手动适配FormattedLogValues。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 07:10:14