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

Sin*_*Sin 5 c# nsubstitute azure-cosmosdb

我正在为我的应用程序编写数据访问层,并尝试模拟 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);
    }
  }
Run Code Online (Sandbox Code Playgroud)

我试图模拟这样的依赖项(简化):

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);
Run Code Online (Sandbox Code Playgroud)

查看 AzureCosmosDB SDK 文档,似乎有一个用于模拟的 FeedResponse 构造函数,它将 IEnumerable 作为参数,但是 NSubstitute 抱怨告诉我,当我尝试传入要使用的列表时,它找不到这个构造函数。有没有替代方法可以将一些 IEnumerable 作为 FeedResponse 提供?我哪里错了?

res*_*mad 5

我还通过模拟模拟GetEnumerator调用来解决这个问题FeedResponse。但是,需要记住的是,如果您只是设置mockFeedIterator.HasMoreResults(true),您最终会陷入无限循环。

我通过使用 Moq 的Callback方法功能解决了这个问题。我将HasMoreResults方法配置为返回 true,然后在该ReadNextAsync方法上设置回调以重新配置HasMoreResults为返回 false。这样,它将while第一次进入循环,根据模拟GetEnumerator方法填充返回集合,然后退出循环并将该集合返回给测试方法。

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);
Run Code Online (Sandbox Code Playgroud)


Sin*_*Sin 1

无论如何,我通过更改代码来访问从 CosmosDB 收到的 FeedResponse 上的 Resource 字段来解决这个问题。在我的测试中,我能够模拟 Resource 的返回值并获得所需的结果。