Mandar Nagarkar
Mandar Nagarkar

Reputation: 143

Mocking GetItemLinqQueryable and Extension method ToFeedIterator()

We are using Azure cosmos client V3. For fetching data we are using GetItemLinqQueryable and ToFeedIterator for making it Async. It works well however while mocking/unit testing we are getting error related to ToFeedIterator

Code:

IOrderedQueryable<T> linqQueryable = _container.GetItemLinqQueryable<T>(requestOptions: requestOptions);
var feedIterator = linqQueryable.Where(predicate).ToFeedIterator();

For mocking UnitTestCode Code:

var _mockResponse = new Mock<ItemResponse<Test>>();
mockContainer.Setup(x => x.GetItemLinqQueryable<Test>(It.IsAny<bool>(), It.IsAny<string>(), It.IsAny<QueryRequestOptions>())).Returns(queryable);

It does return 1 records from GetItemLinqQueryable however ToFeedIterator() fails saying System.ArgumentOutOfRangeException: 'ToFeedIterator is only supported on cosmos LINQ query operations Parameter name: linqQuery'

Upvotes: 10

Views: 6756

Answers (2)

Cameron Tinker
Cameron Tinker

Reputation: 9789

I too recently had some Cosmos tests I needed working. I followed the linked approach in Scott's answer and came up with the following:
ICosmosLinqQuery.cs

public interface ICosmosLinqQuery
{
    FeedIterator<T> GetFeedIterator<T>(IQueryable<T> query);
}

Real implementation of CosmosLinqQuery:

public class CosmosLinqQuery : ICosmosLinqQuery
{
    public FeedIterator<T> GetFeedIterator<T>(IQueryable<T> query)
    {
        return query.ToFeedIterator();
    }
}

Example fake implementation with Moq:

var documents = new List<MyDocument>() { myDocument };

var mockFeedResponse = new Mock<FeedResponse<MyDocument>>();
mockFeedResponse.Setup(x => x.GetEnumerator())
                .Returns(documents.GetEnumerator());

var mockFeedIterator = new Mock<FeedIterator<MyDocument>>();
mockFeedIterator.SetupSequence(m => m.HasMoreResults).Returns(true).Returns(false);
mockFeedIterator.Setup(m => m.ReadNextAsync(CancellationToken.None)).ReturnsAsync(mockFeedResponse.Object);

var mockCosmosLinqQuery = new Mock<ICosmosLinqQuery>();
mockCosmosLinqQuery.Setup(x => x.GetFeedIterator(query))
                   .Returns(mockFeedIterator.Object);

The key to ICosmosLinqQuery is being able to substitute the implementation during testing and inject a real implementation within your application's services.
Registering your real implementation:

services.AddTransient<ICosmosLinqQuery, CosmosLinqQuery>();

Upvotes: 2

Scott
Scott

Reputation: 769

I ran into this same issue. Check out the comments in this github issue 893 in the azure-cosmos-dotnet-v3 repo. I ended up following approach suggested here.

Upvotes: 8

Related Questions