How do I Moq IFindFluent so this call to ToListAsync works?
Asked Answered
P

3

11

I am unit testing a wrapper to the MongoDB C# driver. I have this line of code:

Collection.Find(predicate).ToListAsync();

Where Collection is of type IMongoCollection<T> and Find(predicate) returns an instance implementing IFindFluent<T, T>. ToListAsync() is an extension to turn the results into a list, I assume.

I am attempting to write unit tests, and I am stumped on handling this. I can't make a wrapper class because that's what I'm working on. I would prefer to either make it so ToListAsync() returns a created list OR to mock the Find() to return something that can be made a list of.

Pierian answered 28/7, 2015 at 1:30 Comment(1)
This answered here on this post Moq IFindFluentKatekatee
P
2

I wound up making a little abstraction layer for this, since I couldn't find anything suitable and asking for help yielded no answers.

I created an interface/implementation pair called AppCollection specifically to handle the MongoDB interface. IAppCollection would have a method for IAppCollection.ToList(predicate), and the AppCollection would run the Collection.Find(predicate).ToListAsync(); call, returning the list. Later, it was a trivial matter to mock the IAppCollection to make sure the right calls were being made. While I couldn't test the predicates in native LINQ, I could at least compile the predicates and compare them to passing/failing objects.

Pierian answered 8/2, 2017 at 4:25 Comment(1)
I am struggling with mocking IFindFluent as well and came across your post. Would you be able to provide me your implementation of IAppCollection interface in order to put more light on your solution? Thanks in advance for your helpFooted
S
3

If anyone would struggle with getting it to work, what I did to mock Find() method was:

[TestFixture]
class QueryControllerTests
{
    private IOptions<MongoSettings> _mongoSettings;
    private QueryController _queryController;
    private Mock<IFakeMongoCollection> _fakeMongoCollection;
    private Mock<IFindFluent<BsonDocument, BsonDocument>> _fakeCollectionResult;

    [OneTimeSetUp]
    public void Setup()
    {
        _fakeMongoCollection = new Mock<IFakeMongoCollection>();
        _fakeCollectionResult = new Mock<IFindFluent<BsonDocument, BsonDocument>>();

    }
}

where IFakeMongoCollection is:

public interface IFakeMongoCollection : IMongoCollection<BsonDocument>
{
    IFindFluent<BsonDocument, BsonDocument> Find(FilterDefinition<BsonDocument> filter, FindOptions options);
}
Sensibility answered 26/11, 2018 at 9:18 Comment(1)
This looks like it has potential, but could you provide a little more context on how to use the mock?Agnostic
P
2

I wound up making a little abstraction layer for this, since I couldn't find anything suitable and asking for help yielded no answers.

I created an interface/implementation pair called AppCollection specifically to handle the MongoDB interface. IAppCollection would have a method for IAppCollection.ToList(predicate), and the AppCollection would run the Collection.Find(predicate).ToListAsync(); call, returning the list. Later, it was a trivial matter to mock the IAppCollection to make sure the right calls were being made. While I couldn't test the predicates in native LINQ, I could at least compile the predicates and compare them to passing/failing objects.

Pierian answered 8/2, 2017 at 4:25 Comment(1)
I am struggling with mocking IFindFluent as well and came across your post. Would you be able to provide me your implementation of IAppCollection interface in order to put more light on your solution? Thanks in advance for your helpFooted
S
0
var returnList = new List<DbRecord>();

//add your records to the list

           // Mocking the IAsyncCursor that ToListAsync would internally use
           var mockCursor = new Mock<IAsyncCursor<DbRecord>>();
           mockCursor.SetupSequence(x => x.MoveNextAsync(It.IsAny<CancellationToken>()))
               .ReturnsAsync(true)  
               .ReturnsAsync(false); 

           mockCursor.Setup(x => x.Current)
               .Returns(returnList);

now you can return it from your Mock<IMongoCollection<T>>

            mockMongoCollection.Setup(m => m.FindAsync(It.IsAny<FilterDefinition<DbRecord>>(),
                                                       It.IsAny<FindOptions<DbRecord>>(),
                                                       It.IsAny<CancellationToken>()))
                               .ReturnsAsync(mockCursor.Object);
Splendiferous answered 9/8 at 12:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.