如何使用Moq模拟ResourceGroupCollection对象?
问题:Mock Azure SDK的ResourceGroupCollection使其枚举返回指定ResourceGroupResource
业务代码中通过GetResourceGroups()获取ResourceGroupCollection实例,再用FirstOrDefault枚举筛选资源组:
SubscriptionResource subscription = await armClient.GetDefaultSubscriptionAsync(); var resourceGroup = subscription.GetResourceGroups().FirstOrDefault(rg => rg.Data.Name.Equals(resourceGroupName));
已完成部分Mock逻辑,但不清楚如何将Mock的ResourceGroupResource实例加入ResourceGroupCollection的Mock对象,使得枚举时能返回该实例。当前测试代码如下:
this.resourceGroupCollectionMock = new Mock<ResourceGroupCollection>() { CallBase = true }; Mock<ResourceGroupResource> adfResource = new Mock<ResourceGroupResource>(); ResourceGroupData rgData = ResourceManagerModelFactory.ResourceGroupData(resourceIdentifier, resourceGroupName); adfResource.Setup(x => x.Data).Returns(rgData); this.subscriptionResourceMock.Setup(x => x.GetResourceGroups()).Returns(this.resourceGroupCollectionMock.Object);
解决方案
由于ResourceGroupCollection实现了IEnumerable<ResourceGroupResource>,只需Mock其GetEnumerator()方法,让它返回包含目标Mock实例的枚举器即可。
修改后的完整测试代码:
// 创建并配置目标ResourceGroupResource Mock实例 Mock<ResourceGroupResource> adfResource = new Mock<ResourceGroupResource>(); ResourceGroupData rgData = ResourceManagerModelFactory.ResourceGroupData(resourceIdentifier, resourceGroupName); adfResource.Setup(x => x.Data).Returns(rgData); // 将Mock实例存入列表,用于生成枚举器 var resourceGroupsList = new List<ResourceGroupResource> { adfResource.Object }; // Mock ResourceGroupCollection的枚举器方法 this.resourceGroupCollectionMock = new Mock<ResourceGroupCollection>() { CallBase = true }; resourceGroupCollectionMock.Setup(x => x.GetEnumerator()) .Returns(resourceGroupsList.GetEnumerator()); // 关联Subscription与ResourceGroupCollection的Mock this.subscriptionResourceMock.Setup(x => x.GetResourceGroups()).Returns(this.resourceGroupCollectionMock.Object);
额外说明:支持异步枚举
如果业务代码中使用了异步枚举(比如await foreach),需要额外MockGetAsyncEnumerator()方法:
// 手动包装同步枚举器为异步枚举器(可复用的简单实现) public class AsyncEnumerator<T> : IAsyncEnumerator<T> { private readonly IEnumerator<T> _enumerator; public AsyncEnumerator(IEnumerator<T> enumerator) => _enumerator = enumerator; public T Current => _enumerator.Current; public ValueTask DisposeAsync() { _enumerator.Dispose(); return ValueTask.CompletedTask; } public ValueTask<bool> MoveNextAsync() => ValueTask.FromResult(_enumerator.MoveNext()); } // 在Mock中添加异步枚举的配置 resourceGroupCollectionMock.Setup(x => x.GetAsyncEnumerator(default)) .Returns(new AsyncEnumerator<ResourceGroupResource>(resourceGroupsList.GetEnumerator()));
内容的提问来源于stack exchange,提问作者JasonFan
相关产品推荐
相关产品推荐

