单元测试 ServiceBus.Message。如何设置 SystemProperties.LockToken 的值?

Gir*_*riB 11 c# azureservicebus azure-servicebus-queues

我想测试我使用 QueueClient 注册的消息处理程序回调queueClient.RegisterMessageHandler(MyCallBack, messageHandlerOptions)

public Task MyCallBack(Message msg, CancellationToken token)
{
   // Read msg. Do something

   // Since everything ran fine, complete the msg.
   await _client.CompleteAsync(msg.SystemProperties.LockToken);
}
Run Code Online (Sandbox Code Playgroud)

现在作为我的单元测试的一部分,我调用MyCallBack. 因为我传递了一个有效的消息。我期待client.CompleteAsync()被召唤。但是测试会抛出异常。

System.InvalidOperationException: Operation is not valid due to the current state of the object.
Run Code Online (Sandbox Code Playgroud)

这是因为,msg.SystemProperties.LockToken设置(这是因为消息没有被实际上从一个队列中与客户端读取ReceiveMode.PeekLock模式)。

有没有办法设置/模拟它,以便我可以使用虚拟字符串作为令牌运行我的测试?


PS:我知道我可以msg.SystemProperties.IsLockTokenSet在实际访问 LockToken 字段之前检查;但即使在那种情况下,如果_client.CompleteAsync()被调用,我也永远无法进行单元测试。

And*_*ord 19

以下是创建用于测试的消息和设置 LockToken 的方法:

var message = new Message();
var systemProperties = message.SystemProperties;
var type = systemProperties.GetType();
var lockToken = Guid.NewGuid();
type.GetMethod("set_LockTokenGuid", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(systemProperties, new object[] { lockToken });
type.GetMethod("set_SequenceNumber", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(systemProperties, new object[] { 0 });
Run Code Online (Sandbox Code Playgroud)

我希望我能够想出一些不涉及反思的东西。


Gir*_*riB 4

我创建了一个包装方法GetLockToken(),如果在消息上设置了该LockToken字符串,则返回该字符串,否则返回 null(而不是抛出异常)。

private string GetLockToken(Message msg)
{
    // msg.SystemProperties.LockToken Get property throws exception if not set. Return null instead.
    return msg.SystemProperties.IsLockTokenSet ? msg.SystemProperties.LockToken : null;
}
Run Code Online (Sandbox Code Playgroud)

原来的方法调用CompleteAsync()现在修改为:

await _client.CompleteAsync(GetLockToken(message));
Run Code Online (Sandbox Code Playgroud)

注意:上述更改不会改变预期行为!在生产场景中,调用CompleteAsync(null)仍然会抛出异常:)(根据需要)。

通过上述更改,现在我可以这样设置我的模拟:

var mock= new Mock<IQueueClient>();
mock.Setup(c => c.CompleteAsync(/*lockToken*/ null))
               .Returns(Task.CompletedTask);
Run Code Online (Sandbox Code Playgroud)