.net - JsonConverter 在集成测试中不起作用

标签 .net integration-testing jsonconvert

我已启用我的 API 以使用字符串值序列化/反序列化枚举。为此,我已将 JsonStringEnumConverter 添加到 API 的 Startup 类中受支持的 JsonConverter 列表中:

.AddJsonOptions(opts =>
{
    var enumConverter = new JsonStringEnumConverter();
    opts.JsonSerializerOptions.Converters.Add(enumConverter);
});

它工作正常 - 我的 API 成功地将枚举序列化和反序列化为字符串。

现在 - 我正在尝试为我的 API 构建集成测试并遇到一些问题。 我正在使用 HttpContentJsonExtensions.ReadFromJsonAsync 反序列化 API 响应,但枚举属性引发异常。

问题很明显 - HttpContentJsonExtensions.ReadFromJsonAsync 不知道 API 使用的转换器列表(因为,正如我之前提到的,我已经添加了 JsonStringEnumConverter 到支持的转换器列表,它工作正常)。

如果我在测试函数中这样做:

var options = new System.Text.Json.JsonSerializerOptions();
options.Converters.Add(new JsonStringEnumConverter());
SomeClass result= await response.Content.ReadFromJsonAsync<SomeClass>(options);

然后枚举属性被反序列化,没有抛出异常。但是现在,ReadFromJsonAsync 只知道 JsonStringEnumConverter 而不知道 API 使用的其他 JSON 转换器(如 Guid 转换器)

如何确保 HttpContentJsonExtensions.ReadFromJsonAsync 能够使用 API 使用的所有 JSON 转换器?

谢谢!

最佳答案

不幸的是,没有办法开箱即用。原因是 System.Text.Json API 的“设计者”决定以一种令人难以置信的莫名其妙的举动使所述 API 静态化——可能是为了模仿众所周知的 Newtonsoft.Json——但静态 API 当然不能携带和他们一起声明。有关更多上下文,我 refer you to the feature request to fix this poor design .

我实际上想出了 a solution在那个 FR 中,自从我编造它以来我已经做了一些调整:

public interface IJsonSerializer
{
    JsonSerializerOptions Options { get; }

    Task<T> DeserializeAsync<T>(Stream utf8Json, CancellationToken cancellationToken);

    // other methods elided for brevity
}

public class DefaultJsonSerializer : IJsonSerializer
{
    private JsonSerializerOptions _options;
    public JsonSerializerOptions Options
        => new JsonSerializerOptions(_options); // copy constructor so that callers cannot mutate the options

    public DefaultJsonSerializer(IOptions<JsonSerializerOptions> options)
        => _options = options.Value;

    public async Task<T> DeserializeAsync<T>(Stream utf8Json, CancellationToken cancellationToken = default)
        => await JsonSerializer.DeserializeAsync<T>(utf8Json, Options, cancellationToken);

    // other methods elided for brevity
}

本质上,您定义了一个包装接口(interface),其方法签名与 JsonSerializer 的静态方法签名相同(减去 JsonSerializerOptions 参数,因为您希望使用类上定义的参数) ,然后是所述接口(interface)的默认实现,它委托(delegate)给静态 JsonSerializer 方法。将接口(interface)映射到 Startup.ConfigureServices 中的实现,而不是在需要处理 JSON 的类中调用静态 JsonSerializer 方法,而是将 JSON 接口(interface)注入(inject)到这些类中,然后使用它。

鉴于您正在使用 HttpContentJsonExtensions,您还需要定义您自己的扩展类的包装版本,该扩展类复制其方法签名但将其 JsonSerializerOptions 参数替换为JSON 序列化接口(interface)的实例,然后将所述接口(interface)的选项传递给底层 HttpContentJsonExtensions 实现:

public static class IJsonSerializerHttpContentJsonExtensions
{
    public static Task<object?> ReadFromJsonAsync(this HttpContent content, Type type, IJsonSerializer serializer, CancellationToken cancellationToken = default)
        => HttpContentJsonExtensions.ReadFromJsonAsync(content, type, serializer.Options, cancellationToken);

    // other methods elided for brevity
}

痛吗?是的。没必要吗?也是的。愚蠢吗?第三次,是的。但这就是微软。

关于.net - JsonConverter 在集成测试中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68574418/

相关文章:

.net - 你可以在没有办公室的情况下安装 Office 2007 PIA

c# - 如何获取下一个星期日的日期?

oracle - 用于集成测试的嵌入式或托管 Oracle 实例

testing - 使用服务器测试不同编程语言的客户端的最佳方法是什么?

java - 即使在排除单元测试之后,单元测试也会在集成测试阶段执行

c# - System.Text.Json:将 JSON 转换为十进制值 "NA"

c# - 在对象成为孤立对象之前,我是否需要从对象中删除事件订阅?

.net - 使用 .NET 中的二维条码创建 pdf 文档