我希望为以下课程创建单元测试:
public class ServiceBusClient {
private readonly IMessageReceiver messageReceiver;
private readonly int maximumMessages;
public ServiceBusClient(IMessageReceiver messageReceiver, int maximumMessages) {
this.messageReceiver = messageReceiver;
this.maximumMessages = maximumMessages;
}
public async Task<List<EnergyUser>> ReceiveEnergyUsersAsync() {
List<EnergyUser> energyUsers = new List<EnergyUser>();
List<string> lockTokens = new List<string>();
this.ReceiveMessages()
.ForEach((message) => {
if (message.Body != null) {
energyUsers.Add(JsonConvert.DeserializeObject<EnergyUser>(Encoding.UTF8.GetString(message.Body)));
}
lockTokens.Add(message.SystemProperties.LockToken);
});
_ = this.messageReceiver.CompleteAsync(lockTokens);
return await Task.FromResult(energyUsers);
}
private List<Message> ReceiveMessages() {
return this.messageReceiver.ReceiveAsync(this.maximumMessages)
.GetAwaiter()
.GetResult()
.ToList();
}
}
可以看出,它取决于Microsoft.Azure.ServiceBus.Core.IMessageReceiver
.
我第一次尝试模拟这个是使用Moq
。我希望如果我创建一个new Mock<IMessageReceiver>()
,我应该能够将它注入public ServiceBusClient(IMessageReceiver messageReceiver, int maximumMessages)
,但编译器却告诉我“错误 CS1503 参数 1:无法从 'Moq.Mock' 转换为 'Microsoft.Azure.ServiceBus.Core.IMessageReceiver”......
然后我想我应该尝试手动模拟该类:
internal class MockMessageReceiver : IMessageReceiver {
public int ReceivedMaxMessgeCount { get; set; }
public IList<Message> ReturnMessages { get; set; }
Task<IList<Message>> IMessageReceiver.ReceiveAsync(int maxMessageCount) {
this.ReceivedMaxMessgeCount = maxMessageCount;
return Task.FromResult(this.ReturnMessages);
}
public IEnumerable<string> ReceivedLockTokens { get; set; }
Task IMessageReceiver.CompleteAsync(IEnumerable<string> lockTokens) {
this.ReceivedLockTokens = lockTokens;
return Task.Delay(1);
}
// Many functions which do nothing just to satisfy the bloated interface.
}
这将使我能够成功提供消息,除非我提供的消息不包含 SystemProperties,因此 ServiceBusClient 将在以下位置抛出错误lockTokens.Add(message.SystemProperties.LockToken)
.
事实证明,Microsoft.Azure.ServiceBus.Message
实现不提供设置器public SystemPropertiesCollection SystemProperties
,因此要设置它(除非有人有更好的方法),我需要创建自己的 Message 实现:
public class MockMessage : Message {
public MockMessage(byte[] body) => base.Body = body;
public new SystemPropertiesCollection SystemProperties {
get { return this.SystemProperties; }
set { this.SystemProperties = value; }
}
}
现在,我可以初始化 SystemPropertiesCollection,但问题是 SystemPropertiesCollection 中没有属性实际上包含设置,因此我的测试仍然会失败。
然后我想:让我们为“SystemPropertiesCollection”创建一个模拟(不要介意我们开始在“太多模拟”的危险水域中游泳......但是当我尝试扩展此类时,我的编译器会抱怨,因为 SystemPropertiesCollection 是实际上是一个密封类,所以我无法扩展它。
所以,现在我回到了第一点。
有什么想法可以为 ServiceBusClient 创建良好的单元测试吗?