我正在为我的应用程序编写数据访问层,并尝试模拟CosmosDB SDK依赖项以进行单元测试。我将NUnit与NSubstitute一起使用,并且遇到了我尝试模拟Container.GetItemQueryIterator的返回值的问题。
我已成功提供了一个模拟feedIterator作为对该调用的响应,并提供了一个模拟feedResponse作为feedIterator.ReadNextAsync的返回值,但是我不知道如何将任何类型的值注入FeedResponse中进行测试
我要测试的代码如下:
var feedIterator = container.GetItemQueryIterator<T>(queryDefinition);
while (feedIterator.HasMoreResults){
result.success = true;
foreach (var item in await feedIterator.ReadNextAsync()){
list.Add(item);
}
}
我试图模拟这种依赖关系(简化):
this.mockFeedResponse = Substitute.For<FeedResponse<T>>(this.mockApplicationList);
this.mockFeedIterator = Substitute.For<FeedIterator<T>>();
this.mockFeedIterator.ReadNextAsync().ReturnsForAnyArgs(Task.FromResult(this.mockFeedResponse));
this.mockFeedIterator.HasMoreResults.Returns(true);
查看AzureCosmosDB SDK文档,似乎有一个FeedResponse构造函数,该构造函数将IEnumerable作为参数,但是NSubstitute抱怨告诉我在尝试传递要使用的列表时找不到该构造函数。有没有其他方法可以将IEnumerable作为FeedResponse提供?我要去哪里错了?
答案 0 :(得分:3)
我还通过模拟GetEnumerator
模拟中的FeedResponse
调用来解决了这个问题。但是,要记住的一点是,如果仅设置mockFeedIterator.HasMoreResults(true)
,则会陷入无限循环。
我通过使用Moq的Callback
方法功能解决了这个问题。我将HasMoreResults
方法配置为返回true,然后在ReadNextAsync
方法上设置了一个回调以将HasMoreResults
重新配置为返回false。这样,它将首次进入while
循环,基于模拟的GetEnumerator
方法填充return集合,然后退出循环并将该集合返回到test方法。
var myItems = new List<MyItem>
{
new MyItem(),
new MyItem()
};
var feedResponseMock = new Mock<FeedResponse<MyItem>>();
feedResponseMock.Setup(x => x.GetEnumerator()).Returns(myItems.GetEnumerator());
var feedIteratorMock = new Mock<FeedIterator<MyItem>>();
feedIteratorMock.Setup(f => f.HasMoreResults).Returns(true);
feedIteratorMock
.Setup(f => f.ReadNextAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(feedResponseMock.Object)
.Callback(() => feedIteratorMock
.Setup(f => f.HasMoreResults)
.Returns(false));
var containerMock = new Mock<Container>();
containerMock
.Setup(c => c.GetItemQueryIterator<MyItem>(
It.IsAny<QueryDefinition>(),
It.IsAny<string>(),
It.IsAny<QueryRequestOptions>()))
.Returns(feedIteratorMock.Object);
答案 1 :(得分:0)
它的价值-我通过更改代码以访问从CosmosDB接收的FeedResponse上的Resource字段来解决此问题。在测试中,我可以模拟Resource的返回值并获得所需的结果。
答案 2 :(得分:0)
您可以模拟ReadNextAsync
以返回仅定义了FeedResponse
的{{1}}的模拟。然后,您创建的GetEnumerator()
中的GetEnumerator
将被传递到List
的基础实现中。
下面的示例使用foreach
,但是您应该能够在实现中执行类似的操作。
Moq