为包含抽象类型的消息编写消费者测试

问题描述 投票:0回答:1

我目前正在尝试将消费者驱动的契约测试引入现有的 C# 代码库。 目前我只考虑测试messages

在尝试为某些消息创建消费者测试时,我遇到了抽象类型的问题。

让我用一个例子来解释一下。

假设我们有以下消息:

public abstract record KeyValuePair(string Key);
public record IntegerKeyValuePair(string Key, int IntegerValue) : KeyValuePair(Key);
public record DoubleKeyValuePair(string Key, double DoubleValue) : KeyValuePair(Key);

public record Message(KeyValuePair[] KeyValuePairs);

现在我们编写以下消费者测试:

public class StackOverflowConsumerTest
{
    private readonly IMessagePactBuilderV3 _pact;

    public StackOverflowConsumerTest()
    {
        this._pact = Pact.V3(
                "StackOverflowConsumer",
                "StackOverflowProvider",
                new PactConfig { PactDir = "./pacts/" })
            .WithMessageInteractions();
    }

    [Fact]
    public void ShouldReceiveExpectedMessage()
    {
        var message = new
        {
            KeyValuePairs = Match.MinType(
                new
                {
                    Key = Match.Type("SomeValue"),
                    DoubleValue = Match.Decimal(12.3)
                }, 1)
        };

        _pact
            .ExpectsToReceive(nameof(Message))
            .WithJsonContent(message)
            .Verify<Message>(msg =>
            {
                Assert.Equal(new DoubleKeyValuePair("SomeValue", 12.3), msg.KeyValuePairs.Single());
            });
    }
}

运行此 sonsumer 测试将会失败,因为我无法从 Pact.Net + Newtonsoft 生成的 JSON 表示中反序列化消息:

Newtonsoft.Json.JsonSerializationException: Could not create an instance of type PactNet.Learning.KeyValuePair. Type is an interface or abstract class and cannot be instantiated.

我通常会通过更改序列化器设置以包含序列化的实际类型来处理此类情况。然而,这里实际的对象从未真正传递给序列化器。相反,它接收一些动态类型结构,其中包含我用预期值定义的匹配器。 有没有一种方法可以使用我忽略的 Pact.Net 匹配器来处理抽象类型,或者这根本不可能?

解决我的问题的一个方法可能是“重构消息”,但这不是我现在能做的。

pact pact-net
1个回答
0
投票

如果我正确理解 Pact.NET 库(并且我对此并不完全确定),那么有问题的反序列化应该发生在 ConfiguredMessageVerifier.MessageReified

如果是这种情况,您可以在 JsonSerializerSettings 初始化(您的第三个参数)中使用自定义

Pact.V3
指定
PactConfig.DefaultJsonSettings

应该重载

withJsonContent
方法以允许传递自定义
JsonSerializerSettings

我对 .NET 不太熟悉,所以我不确定配置自定义

JsonSerializerSettings
是否足以正确序列化和反序列化您的抽象类型。据我所知,注入整个序列化/反序列化方法而不是依赖于
Newtonsoft.Json
是不可能的。


编辑:这并不能解决问题,因为使用了

dynamic
对象(参见下面的答案)。这是一个如何解决它的理论方法(我还没有尝试过)。灵感来自这篇文章:https://stackoverflow.com/a/65261072/12256497

是否可以引入专门用于契约的记录并使用它们来代替动态对象?示意性地(我不知道 Matcher 类型是否正确):

public abstract record PactKeyValuePair(StringMatcher Key);
public record IntegerPactKeyValuePair(StringMatcher Key, IntMatcher IntegerValue) : PactKeyValuePair(Key);
public record DoublePactKeyValuePair(StringMatcher Key, DecimalMatcher DoubleValue) : PactKeyValuePair(Key);

public record PactMessage(PactKeyValuePair[] KeyValuePairs);

然后您可以使用执行以下操作的

ISerializationBinder
注册自定义
JsonSerializerSettings

  • PactKeyValuePair
    方法中将
    "WorkaroundKeyValuePair"
    序列化为人工 $type(例如
    BindToName
  • KeyValuePair
    方法中从人工 $type 反序列化为
    BindToType
    (因此是没有匹配器的原始类型)。
© www.soinside.com 2019 - 2024. All rights reserved.