如何Mock DocumentClient的CreateDocumentQuery与AsDocumentQuery
解决Mock DocumentClient时的IDocumentQuery类型转换问题
我来帮你搞定这个Mock DocumentClient的麻烦——你遇到的类型转换错误,根源是直接用Linq的AsQueryable()返回的是EnumerableQuery<T>,它并没有实现IDocumentQuery<T>接口,自然没法强制转换。下面是具体的可行方案:
核心思路:Mock IDocumentQuery接口
我们不直接MockDocumentClient的具体实现,而是针对它返回的IDocumentQuery<T>接口做Mock,同时补上IQueryable<T>的必要实现(因为IDocumentQuery<T>继承自IQueryable<T>)。
步骤1:编写Mock IDocumentQuery的辅助方法
这个方法可以帮你快速生成带有预设数据的Mock查询对象:
private static Mock<IDocumentQuery<T>> GetMockDocumentQuery<T>(List<T> testData) { var mockQuery = new Mock<IDocumentQuery<T>>(); // 模拟ExecuteNextAsync的返回序列:先返回测试数据,再返回空列表表示无更多结果 mockQuery.SetupSequence(q => q.ExecuteNextAsync<T>(It.IsAny<CancellationToken>())) .ReturnsAsync(new FeedResponse<T>(testData)) .ReturnsAsync(new FeedResponse<T>(new List<T>())); // 配合ExecuteNextAsync,模拟HasMoreResults的状态变化 mockQuery.SetupSequence(q => q.HasMoreResults) .Returns(true) .Returns(false); // 实现IQueryable<T>的必要成员,避免接口实现缺失的问题 var queryableData = testData.AsQueryable(); mockQuery.As<IQueryable<T>>().Setup(q => q.Provider).Returns(queryableData.Provider); mockQuery.As<IQueryable<T>>().Setup(q => q.Expression).Returns(queryableData.Expression); mockQuery.As<IQueryable<T>>().Setup(q => q.ElementType).Returns(queryableData.ElementType); mockQuery.As<IQueryable<T>>().Setup(q => q.GetEnumerator()).Returns(queryableData.GetEnumerator()); return mockQuery; }
步骤2:Mock DocumentClient的CreateDocumentQuery方法
接下来把Mock的查询对象绑定到DocumentClient的方法上:
// 建议你的业务类依赖IDocumentClient接口,而不是具体的DocumentClient类,更易测试 var mockDocumentClient = new Mock<IDocumentClient>(); // 准备你的测试数据 var testEvents = new List<YourEventEntity> { new YourEventEntity { Id = "event-1", Title = "测试事件1" }, new YourEventEntity { Id = "event-2", Title = "测试事件2" } }; // 生成Mock的IDocumentQuery var mockEventsQuery = GetMockDocumentQuery(testEvents); // 设置CreateDocumentQuery返回我们的Mock查询 mockDocumentClient.Setup(client => client.CreateDocumentQuery<YourEventEntity>( It.IsAny<Uri>(), It.IsAny<string>(), It.IsAny<FeedOptions>())) .Returns(mockEventsQuery.Object);
步骤3:在测试中使用Mock对象
现在你可以把这个Mock的IDocumentClient注入到待测试类里,调用方法时ExecuteNextAsync就会返回你预设的测试数据了:
// 初始化待测试类,传入Mock的DocumentClient var yourService = new YourEventService(mockDocumentClient.Object); // 调用待测试的方法 var result = await yourService.GetEventsAsync(); // 断言结果符合预期 Assert.Equal(2, result.Count());
补充说明
你之前碰到的JTokenEx方案应该是比较旧的实现,现在用Moq直接MockIDocumentQuery<T>是更简洁、易维护的方式。另外,建议你的业务类尽量依赖IDocumentClient接口而非具体类,这是依赖倒置原则的实践,也会让测试变得更轻松。
内容的提问来源于stack exchange,提问作者Jim Brown
相关产品推荐
相关产品推荐

