如何使用 NSubstitute 在单元测试中模拟 MassTransit 标头值

时间:2021-06-09 07:16:05

标签: c# unit-testing rabbitmq masstransit nsubstitute

我正在尝试创建一个单元测试来测试我的 MassTransit (RabbitMq) 消费者。我的消费者需要一个名为 UserName 的总线头键。我已将我的消费者类简化如下。我需要找到一种方法来模拟总线头数据,否则测试在执行 context.Headers.TryGetHeader("UserName", out object value)

时总是会引发异常

我正在使用 NSubstitute 模拟库。那么如何模拟 ConsumeContext<MyDataObject> 类型并设置模拟标头值?我更喜欢 NSubstitute

的解决方案
public class MyDataObjectCommand
{
    public string MyProperty { get; set; }
}

// Consumer class
public class MyConsumer : IConsumer<MyDataObjectCommand>
{
    private readonly IHubContext<MessageHub> _hubContext;

    public MyConsumer(IHubContext<MessageHub> hubContext)
    {
        _hubContext = hubContext;
    }

    public async Task Consume(ConsumeContext<MyDataObjectCommand> context)
    {
        var myProperty = context.Message.MyProperty;
        var userName = TryGetHeader(context, "UserName");
        DoSomethingWith(_hubContext, myProperty, userName);
    }

    private string TryGetHeader(ConsumeContext<MyDataObjectCommand> context, string key, bool errorOnNull = true)
    {
        if (context.Headers.TryGetHeader(key, out object value))
        {
            return Convert.ToString(value);
        }

        if (errorOnNull)
        {
            throw new MyConsumerException(_reportName, $"{key} is not found", _hubContext);
        }

        return null;
    }
}


// Unit Test (I'm using XUnit)
public class MyConsumerTests
{
    private readonly IHubContext<MessageHub> _hubContext;

    public MyConsumerTests()
    {
       _hubContext = Substitute.For<IHubContext<MessageHub>>();
    }

    [Fact]
    public async Task ShouldConsume()
    {
        // arrange
        var mockDataObject = new MyDataObjectCommand() { MyProperty = "x" };

        var harness = new InMemoryTestHarness();
        harness.Consumer(() => new MyConsumer(_hubContext));

        // I need to mock header values on ConsumeContext<MyDataObjectCommand> object here
        // but how do I do it using NSubstitute?
        // context.Headers["UserName"] = "Bob";  ??

        await harness.Start();
        try
        {
            
            // act
            await harness.InputQueueSendEndpoint.Send(mockDataObject);

            // assert
            Assert.True(await harness.Consumed.Any<MyDataObjectCommand>());
            Assert.False(await harness.Consumed.Any<Fault<MyDataObjectCommand>>());
            //Assert.Equal(context.Header["UserName"], "Bob"); How do I do the assertion??
        }
        finally
        {
            await harness.Stop();
        }
    }
}

1 个答案:

答案 0 :(得分:0)

在使用 MassTransit 时不必模拟标头值,只需在使用测试工具发送消息时设置它们即可。对模拟框架的需求绝对

function getProducts() {
  http
    .get(url, (res) => {
      let body = "";
      res.on("data", (chunk) => {
        body += chunk;
      });
      res.on("end", () => {
        try {
          let json = JSON.parse(body);
          console.log(json);
        } catch (error) {
          console.error(error.message);
        }
      });
    })
    .on("error", (error) => {
      console.error(error.message);
    });
} 

当消息传递给消费者时,标头将在 await harness.InputQueueSendEndpoint.Send(mockDataObject, context => context.Headers.Set(“UserName”, “Bob”)); 上可用。

相关问题