gpt4 book ai didi

c# - 如何(我应该)模拟 DocumentClient 进行 DocumentDb 单元测试?

转载 作者:行者123 更新时间:2023-11-30 12:55:31 24 4
gpt4 key购买 nike

从新的 CosmosDb 模拟器中,我得到了一个存储库来执行基本的 documentdb 操作,该存储库被注入(inject)到其他类中。我想对基本查询进行单元测试。

public class DocumentDBRepository<T> where T : class
{
//Details ommited...

public IQueryable<T> GetQueryable()
{
return _client.CreateDocumentQuery<T>(
UriFactory.CreateDocumentCollectionUri(_databaseId, _collectionId),
new FeedOptions { MaxItemCount = -1, EnableCrossPartitionQuery = true });
}

public async Task<IEnumerable<T>> ExecuteQueryAsync(IQueryable<T> query)
{
IDocumentQuery<T> documentQuery = query.AsDocumentQuery();
List<T> results = new List<T>();
while (documentQuery.HasMoreResults)
{
results.AddRange(await documentQuery.ExecuteNextAsync<T>());
}

return results;
}


}

这个存储库需要一个文档客户端才能工作,它也会被注入(inject)到构造函数中。

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

我最初的方法是使用 CosmosDb 模拟器,但这需要模拟器运行,但我不喜欢这种方式,并且会使测试速度变慢。

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

var data = new List<MyDocumentClass>
{
new MyDocumentClass{ Description= "BBB" },
new MyDocumentClass{ Description= "ZZZ" },

}
.AsQueryable()
.OrderBy(q => q.Description);
var client = new Mock<IDocumentClient>();
client.As<IDocumentClient>()
.Setup(foo => foo.CreateDocumentQuery<MyDocumentClass>(It.IsAny<Uri>(), It.IsAny<FeedOptions>()))
.Returns(data);

DocumentDBRepository<MyDocumentClass> repo= new DocumentDBRepository<MyDocumentClass>(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 方法。所以问题是,即使我模拟 .asDocumentQuery() 返回我的对象​​,我也不知道如何为 HasMoreResultsExecuteNextAsync< 提供结果 以便它对我的单元测试有意义。

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

最佳答案

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

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

以下示例展示了如何完成此操作。

[TestClass]
public class DocumentDBRepositoryShould {
/// <summary>
/// Fake IOrderedQueryable IDocumentQuery for mocking purposes
/// </summary>
public interface IFakeDocumentQuery<T> : IDocumentQuery<T>, IOrderedQueryable<T> {

}

[TestMethod]
public async Task ExecuteQueryAsync() {
//Arrange
var description = "BBB";
var expected = new List<MyDocumentClass> {
new MyDocumentClass{ Description = description },
new MyDocumentClass{ Description = "ZZZ" },
new MyDocumentClass{ Description = "AAA" },
new MyDocumentClass{ Description = "CCC" },

};
var response = new FeedResponse<MyDocumentClass>(expected);

var mockDocumentQuery = new Mock<IFakeDocumentQuery<MyDocumentClass>>();
mockDocumentQuery
.SetupSequence(_ => _.HasMoreResults)
.Returns(true)
.Returns(false);

mockDocumentQuery
.Setup(_ => _.ExecuteNextAsync<MyDocumentClass>(It.IsAny<CancellationToken>()))
.ReturnsAsync(response);

var client = new Mock<IDocumentClient>();

client
.Setup(_ => _.CreateDocumentQuery<MyDocumentClass>(It.IsAny<Uri>(), It.IsAny<FeedOptions>()))
.Returns(mockDocumentQuery.Object);

var cosmosDatabase = string.Empty;

var documentsRepository = new DocumentDBRepository<MyDocumentClass>(cosmosDatabase, client.Object);

//Act
var query = documentsRepository.GetQueryable(); //Simple query.

var actual = await documentsRepository.ExecuteQueryAsync(query);

//Assert
actual.Should().BeEquivalentTo(expected);
}
}

关于c# - 如何(我应该)模拟 DocumentClient 进行 DocumentDb 单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48405529/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com