如何(我应该)模拟DocumentClb进行DocumentDbunit testing?

从新的CosmosDb模拟器我得到了一个存储库来执行基本的documentdb操作,这个存储库被注入到其他类。 我想对基本查询进行unit testing。

public class DocumentDBRepository where T : class { //Details ommited... public IQueryable GetQueryable() { return _client.CreateDocumentQuery( UriFactory.CreateDocumentCollectionUri(_databaseId, _collectionId), new FeedOptions { MaxItemCount = -1, EnableCrossPartitionQuery = true }); } public async Task<IEnumerable> ExecuteQueryAsync(IQueryable query) { IDocumentQuery documentQuery = query.AsDocumentQuery(); List results = new List(); while (documentQuery.HasMoreResults) { results.AddRange(await documentQuery.ExecuteNextAsync()); } return results; } } 

此存储库需要一个文档客户端才能工作,它也会在构造函数上注入。

 public DocumentDBRepository(string databaseId, IDocumentClient client) { _client = client; _databaseId = databaseId; _collectionId = GetCollectionName(); } 

我最初的方法是使用CosmosDb模拟器,但这需要模拟器运行我不喜欢并使测试更慢。

我的第二种方法是尝试使用文档客户端的模拟。

 var data = new List { new MyDocumentClass{ Description= "BBB" }, new MyDocumentClass{ Description= "ZZZ" }, } .AsQueryable() .OrderBy(q => q.Description); var client = new Mock(); client.As() .Setup(foo => foo.CreateDocumentQuery(It.IsAny(), It.IsAny())) .Returns(data); DocumentDBRepository repo= new DocumentDBRepository(cosmosDatabase, client.Object); 

使用此存储库的代码如下所示:

 var query = _documentsRepository.GetQueryable() .Where(d => d.Description = description) .OrderByDescending(d => d.description) .Take(100); //Execute query async fails. var result = await _documentsRepository.ExecuteQueryAsync(query); 

它失败是因为存储库尝试将IQueryable转换为IDocumentQuery对象,这对DocumentDb api非常具体(请参阅上面的方法ExecuteQueryAsync )。 稍后,它HasMoreResults它执行HasMoreResults方法。 所以问题是,即使我模拟.asDocumentQuery()来返回我的对象​​,我也不知道如何为HasMoreResultsExecuteNextAsync提供结果,这样我的unit testing才有意义。

我的第三个选择是直接模拟我的存储库而不是DocumentClient对象。 我认为,这将更简单,但我不会测试很多DocumentDb api。

关键是您正在调用的CreateDocumentQuery ,虽然显示为返回IOrderedQueryable ,但封装结果也将从IDocumentQuery派生,这将允许.AsDocumentQuery()工作。

现在通常你不应该嘲笑你不拥有的东西。 但是,在这种情况下,如果您想要完成ExecuteQueryAsync ,您可以创建一个假抽象,允许测试完成。

以下示例显示了如何完成它。

 [TestClass] public class DocumentDBRepositoryShould { ///  /// Fake IOrderedQueryable IDocumentQuery for mocking purposes ///  public interface IFakeDocumentQuery : IDocumentQuery, IOrderedQueryable { } [TestMethod] public async Task ExecuteQueryAsync() { //Arrange var description = "BBB"; var expected = new List { new MyDocumentClass{ Description = description }, new MyDocumentClass{ Description = "ZZZ" }, new MyDocumentClass{ Description = "AAA" }, new MyDocumentClass{ Description = "CCC" }, }; var response = new FeedResponse(expected); var mockDocumentQuery = new Mock>(); mockDocumentQuery .SetupSequence(_ => _.HasMoreResults) .Returns(true) .Returns(false); mockDocumentQuery .Setup(_ => _.ExecuteNextAsync(It.IsAny())) .ReturnsAsync(response); var client = new Mock(); client .Setup(_ => _.CreateDocumentQuery(It.IsAny(), It.IsAny())) .Returns(mockDocumentQuery.Object); var cosmosDatabase = string.Empty; var documentsRepository = new DocumentDBRepository(cosmosDatabase, client.Object); //Act var query = documentsRepository.GetQueryable(); //Simple query. var actual = await documentsRepository.ExecuteQueryAsync(query); //Assert actual.Should().BeEquivalentTo(expected); } }