I'm creating some unit tests for my DAL that uses mongoDB c# driver. The thing is that I have this method that I want to test:
public async virtual Task<IEnumerable<T>> GetAsync(Expression<Func<T, bool>> predicate)
{
return (await Collection.FindAsync(predicate)).ToList();
}
and using Moq I have mocked the collection like this:
var mockMongoCollectionAdapter = new Mock<IMongoCollectionAdapter<Entity>>();
var expectedEntities = new List<Entity>
{
mockEntity1.Object,
mockEntity2.Object
};
mockMongoCollectionAdapter.Setup(x => x.FindAsync(It.IsAny<Expression<Func<Entity,bool>>>(), null, default(CancellationToken))).ReturnsAsync(expectedEntities as IAsyncCursor<Entity>);
but as expectedEntities as IAsyncCursor<Entity>
is null the test is not working.
What is the best way to mock this method and handle the IAsyncCursor?
The official MongoDB Node. js driver allows Node. js applications to connect to MongoDB and work with data. The driver features an asynchronous API which allows you to interact with MongoDB using Promises or via traditional callbacks.
MongoDB is a NoSQL database that is open source. MongoDB is available in two editions. One is MongoDB Open Source, which is free as part of the Open-Source Community, but for the other editions, you must pay a License fee.
Mock the IAsyncCursor<TDocument> interface
so that it can be enumerated. There are not many methods on the interface any way
var mockCursor = new Mock<IAsyncCursor<Entity>>();
mockCursor.Setup(_ => _.Current).Returns(expectedEntities); //<-- Note the entities here
mockCursor
.SetupSequence(_ => _.MoveNext(It.IsAny<CancellationToken>()))
.Returns(true)
.Returns(false);
mockCursor
.SetupSequence(_ => _.MoveNextAsync(It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(true))
.Returns(Task.FromResult(false));
mockMongoCollectionAdapter
.Setup(x => x.FindAsync(
It.IsAny<Expression<Func<Entity, bool>>>(),
null,
It.IsAny<CancellationToken>()
))
.ReturnsAsync(mockCursor.Object); //<-- return the cursor here.
For reference on how the cursor is enumerated take a look at this answer.
How is an IAsyncCursor used for iteration with the mongodb c# driver?
After this you will be able to understand why the mock was setup with sequences for the move next methods.
If it helps anyone else.... off of @Nkosi's mocking answer I implemented the following class
public class MockAsyncCursor<T> : IAsyncCursor<T>
{
private readonly IEnumerable<T> _items;
private bool called = false;
public MockAsyncCursor(IEnumerable<T> items)
{
_items = items ?? Enumerable.Empty<T>();
}
public IEnumerable<T> Current => _items;
public bool MoveNext(CancellationToken cancellationToken = new CancellationToken())
{
return !called && (called = true);
}
public Task<bool> MoveNextAsync(CancellationToken cancellationToken)
{
return Task.FromResult(MoveNext(cancellationToken));
}
public void Dispose()
{
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With