单元测试 ServiceBus.Message。如何设置 SystemProperties.LockToken 的值?
Unit Testing ServiceBus.Message. How to set value for SystemProperties.LockToken?
我想测试使用 queueClient.RegisterMessageHandler(MyCallBack, messageHandlerOptions)
.
向 QueueClient 注册的消息处理程序回调
public Task MyCallBack(Message msg, CancellationToken token)
{
// Read msg. Do something
// Since everything ran fine, complete the msg.
await _client.CompleteAsync(msg.SystemProperties.LockToken);
}
现在,作为单元测试的一部分,我调用 MyCallBack
。因为我传递了 valid 消息。我希望 client.CompleteAsync()
被调用。但是测试抛出异常。
System.InvalidOperationException: Operation is not valid due to the current state of the object.
这是因为msg.SystemProperties.LockToken
未设置(这是因为消息不是实际上从队列中读取ReceiveMode.PeekLock
模式的客户端)。
有没有办法 set/mock 这样我就可以 运行 我的测试使用虚拟字符串作为标记?
PS:我知道我可以在实际访问 LockToken 字段之前检查 msg.SystemProperties.IsLockTokenSet
;但即使在那种情况下,如果 _client.CompleteAsync()
被调用,我也永远无法进行单元测试。
我创建了一个包装器方法 GetLockToken()
如果它在消息上设置 returns LockToken
字符串,否则它 returns 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;
}
原来对CompleteAsync()
的方法调用现在修改为:
await _client.CompleteAsync(GetLockToken(message));
注意:以上更改不会改变预期的行为!在生产场景中,调用 CompleteAsync(null)
仍会抛出异常 :)(根据需要)。
通过以上更改,现在我可以这样设置我的模拟:
var mock= new Mock<IQueueClient>();
mock.Setup(c => c.CompleteAsync(/*lockToken*/ null))
.Returns(Task.CompletedTask);
以下是创建用于测试的消息和设置 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 });
我希望我能够想出一些不涉及反射的东西。
我想测试使用 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);
}
现在,作为单元测试的一部分,我调用 MyCallBack
。因为我传递了 valid 消息。我希望 client.CompleteAsync()
被调用。但是测试抛出异常。
System.InvalidOperationException: Operation is not valid due to the current state of the object.
这是因为msg.SystemProperties.LockToken
未设置(这是因为消息不是实际上从队列中读取ReceiveMode.PeekLock
模式的客户端)。
有没有办法 set/mock 这样我就可以 运行 我的测试使用虚拟字符串作为标记?
PS:我知道我可以在实际访问 LockToken 字段之前检查 msg.SystemProperties.IsLockTokenSet
;但即使在那种情况下,如果 _client.CompleteAsync()
被调用,我也永远无法进行单元测试。
我创建了一个包装器方法 GetLockToken()
如果它在消息上设置 returns LockToken
字符串,否则它 returns 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;
}
原来对CompleteAsync()
的方法调用现在修改为:
await _client.CompleteAsync(GetLockToken(message));
注意:以上更改不会改变预期的行为!在生产场景中,调用 CompleteAsync(null)
仍会抛出异常 :)(根据需要)。
通过以上更改,现在我可以这样设置我的模拟:
var mock= new Mock<IQueueClient>();
mock.Setup(c => c.CompleteAsync(/*lockToken*/ null))
.Returns(Task.CompletedTask);
以下是创建用于测试的消息和设置 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 });
我希望我能够想出一些不涉及反射的东西。