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

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


牧羊人nacy
浏览 123回答 3
3回答

慕尼黑的夜晚无繁华

GetEnumerator我还通过模拟模拟中的呼叫来解决这个问题FeedResponse。但是,需要记住的是,如果您只是设置mockFeedIterator.HasMoreResults(true),您最终会陷入无限循环。我通过使用 Moq 的Callback方法功能解决了这个问题。我将该HasMoreResults方法配置为返回 true,然后在该ReadNextAsync方法上设置回调以重新配置HasMoreResults为返回 false。这样,它将while第一次进入循环,根据模拟GetEnumerator方法填充返回集合,然后退出循环并将该集合返回给测试方法。var myItems = new List<MyItem>{&nbsp; &nbsp; new MyItem(),&nbsp; &nbsp; 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&nbsp; &nbsp; .Setup(f => f.ReadNextAsync(It.IsAny<CancellationToken>()))&nbsp; &nbsp; .ReturnsAsync(feedResponseMock.Object)&nbsp; &nbsp; .Callback(() => feedIteratorMock&nbsp; &nbsp; &nbsp; &nbsp; .Setup(f => f.HasMoreResults)&nbsp; &nbsp; &nbsp; &nbsp; .Returns(false));var containerMock = new Mock<Container>();containerMock&nbsp; &nbsp; .Setup(c => c.GetItemQueryIterator<MyItem>(&nbsp; &nbsp; &nbsp; &nbsp; It.IsAny<QueryDefinition>(),&nbsp; &nbsp; &nbsp; &nbsp; It.IsAny<string>(),&nbsp; &nbsp; &nbsp; &nbsp; It.IsAny<QueryRequestOptions>()))&nbsp; &nbsp; .Returns(feedIteratorMock.Object);

茅侃侃

您可以模拟返回仅已定义的ReadNextAsync模拟。然后,您创建的 的将会传递到 的底层实现。FeedResponseGetEnumerator()GetEnumeratorListforeach以下示例使用Moq,但您应该能够在实现中执行类似的操作。var mockFeedResponse = new Mock<FeedResponse<Thing>>();mockFeedResponse&nbsp; &nbsp; .Setup(x => x.GetEnumerator())&nbsp; &nbsp; .Returns(&nbsp; &nbsp; &nbsp; &nbsp; new List<Thing>&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Thing(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Thing()&nbsp; &nbsp; &nbsp; &nbsp; }.GetEnumerator()&nbsp; &nbsp; );

有只小跳蛙

无论如何,我通过更改代码来访问从 CosmosDB 收到的 FeedResponse 上的 Resource 字段来解决这个问题。在我的测试中,我能够模拟 Resource 的返回值并获得所需的结果。
打开App,查看更多内容
随时随地看视频慕课网APP