I am using unit tests to test DocumentDBRepository
class. I followed this post as an example for the SQL queries use case. But it shows error of
Message: System.InvalidCastException : Unable to cast object of type 'System.Linq.EnumerableQuery to type 'Microsoft.Azure.Documents.Linq.IDocumentQuery
Here's my code for DocumentDBRepository
class
private IDocumentQuery<T> GetQueryBySQL(string queryStr)
{
var uri = UriFactory.CreateDocumentCollectionUri(_databaseId, _collectionId);
var feedOptions = new FeedOptions { MaxItemCount = -1, EnableCrossPartitionQuery = true };
IQueryable<T> filter = _client.CreateDocumentQuery<T>(uri, queryStr, feedOptions);
IDocumentQuery<T> query = filter.AsDocumentQuery();
return query;
}
public async Task<IEnumerable<T>> RunQueryAsync(string queryString)
{
IDocumentQuery<T> query = GetQueryBySQL(queryString);
List<T> results = new List<T>();
while (query.HasMoreResults)
{
results.AddRange(await query.ExecuteNextAsync<T>());
}
return results;
}
Here's my code for my test class
public async virtual Task Test_GetEntitiesAsyncBySQL()
{
var id = "100";
string queryString = "SELECT * FROM c WHERE c.ID = " + id;
var dataSource = new List<Book> {
new Book { ID = "100", Title = "abc"}}.AsQueryable();
Expression<Func<Book, bool>> predicate = t => t.ID == id;
var expected = dataSource.Where(predicate.Compile());
var response = new FeedResponse<Book>(expected);
var mockDocumentQuery = new Mock<DocumentDBRepositoryTest.IFakeDocumentQuery<Book>>();
mockDocumentQuery
.SetupSequence(_ => _.HasMoreResults)
.Returns(true)
.Returns(false);
mockDocumentQuery
.Setup(_ => _.ExecuteNextAsync<Book>(It.IsAny<CancellationToken>()))
.ReturnsAsync(response);
var provider = new Mock<IQueryProvider>();
provider
.Setup(_ => _.CreateQuery<Book>(It.IsAny<Expression>()))
.Returns(mockDocumentQuery.Object);
mockDocumentQuery.As<IQueryable<Book>>().Setup(x => x.Provider).Returns(provider.Object);
mockDocumentQuery.As<IQueryable<Book>>().Setup(x => x.Expression).Returns(dataSource.Expression);
mockDocumentQuery.As<IQueryable<Book>>().Setup(x => x.ElementType).Returns(dataSource.ElementType);
mockDocumentQuery.As<IQueryable<Book>>().Setup(x => x.GetEnumerator()).Returns(() => dataSource.GetEnumerator());
var client = new Mock<IDocumentClient>();
client.Setup(_ => _.CreateDocumentQuery<Book>(It.IsAny<Uri>(), It.IsAny<FeedOptions>()))
.Returns(mockDocumentQuery.Object);
var documentsRepository = new DocumentDBRepository<Book>(client.Object, "100", "100");
//Act
var entities = await documentsRepository.RunQueryAsync(queryString);
//Assert
entities.Should()
.NotBeNullOrEmpty()
.And.BeEquivalentTo(expected);
}
The break point stops at this line of code:
IQueryable<T> filter = _client.CreateDocumentQuery<T>(uri, queryStr, feedOptions);
The filter
variable shows null exception at a lot of its properties and result view shows empty, when it's supposed to show the expected
value that I defined in the test method.
Any clue how to fix it?
The reason you see the error seems quite simple to me.
Here is how you set up the parameters list -
And here is how you call CreateDocumentQuery -
So basically you've missed queryString. Here is what you should do -
The correct
CreateDocumentQuery
overload needs to be set up on the mocked client.The method under test uses
Yet in arranging the test, the client was set up like
That should be changed to
Because of the additional
queryStr
parameter. It could have also used the string parameter directly as an alternative, given that is is being explicitly injected into the method and can be used as part of the expectation.Since the method under test is not using Linq directly when building the query then there is no need to mock/override the query provider as was in a previous iteration of this topic
Here is the completed test after the above changes