如何在CosmosSDK v3 +的FeedResponse中提供模拟值?

时间:2019-09-29 13:54:50

标签: c# azure-cosmosdb nsubstitute

我正在为我的应用程序编写数据访问层,并尝试模拟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提供?我要去哪里错了?

3 个答案:

答案 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