问题描述
我正在尝试创建一个单元测试来测试我的 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();
}
}
}
解决方法
在使用 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”));
上可用。