我有以下课程,我希望为其创建单元测试:
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>' 转换为'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
实现不提供 setter for 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 创建好的单元测试吗?