I have been trying to mock/fake the static method FindAsync() in my Unit test cases using Wrappers, some concepts of Pose. As the static methods cannot be mocked or faked normally. It is not successful.
The code in the repository layer which I want to unit test points to the IMongoCollectionExtension.FindAsync() method.
This is the method I am trying to mock
public async Task<MyClass> GetItem(Guid id)
{
var filter = Builders<MyClass>.Filter.Eq(m => m.Id, id);
var result = await _context.MyCollection.FindAsync(filter);
return result.FirstOrDefault();
}
This FindAsync() is pointing to IMongoCollectionExtensions STATIC class
public static Task<IAsyncCursor<TDocument>> FindAsync<TDocument>(this IMongoCollection<TDocument> collection, FilterDefinition<TDocument> filter, FindOptions<TDocument, TDocument> options = null, CancellationToken cancellationToken = default(CancellationToken));
So as it is pointing to Static class and a static method I started writing wrapper to mock,
First Method tried using Wrapper:
This is wrapper I have created.
public interface IMongoCollectionExtensionsWrapper
{
Task<IAsyncCursor<MyClass>> FindAsync<MyClass>(IMongoCollection<MyClass> collection, FilterDefinition<MyClass> filter, FindOptions<MyClass, MyClass> options = null, CancellationToken cancellationToken = default(CancellationToken));
}
public class MongoCollectionExtensionsWrapper : IMongoCollectionExtensionsWrapper
{
public Task<IAsyncCursor<MyClass>> FindAsync<MyClass>(IMongoCollection<MyClass> collection, FilterDefinition<MyClass> filter, FindOptions<MyClass, MyClass> options = null, CancellationToken cancellationToken = default(CancellationToken))
{
return collection.FindAsync(filter, options, cancellationToken);
}
}
public static class FakeExtensions
{
public static IMongoCollectionExtensionsWrapper defaultmcExtWrapper = new MongoCollectionExtensionsWrapper();
public static Task<IAsyncCursor<MyClass>> FindAsync(this IMongoCollection<MyClass> collection, FilterDefinition<MyClass> filter, FindOptions<MyClass, MyClass> options = null, CancellationToken cancellationToken = default(CancellationToken))
{
return defaultmcExtWrapper.FindAsync(collection, filter, options, cancellationToken);
}
}
As the wrapper was not working properly i checked out free framework Pose to mock static methods. That was not successful too.
Second trial using Pose
Shim findshim = Shim.Replace(() => IMongoCollectionExtensions.FindAsync(Is.A<IMongoCollection<MyClass>>(), filter, null, CancellationToken.None)).With(delegate (IMongoCollection<MyClass> mc, FilterDefinition<MyClass> f, FindOptions<MyClass, MyClass> o, CancellationToken ca) { return Task.FromResult(_fakeOutput.FakedObject); });
NOTE: _fakeOutput is a faked Cursor holding an IEnumerable. It works fine.
PoseContext.Isolate(() =>
{
Task.Run(() =>
{
var exp = Task.FromResult(item1);
var myres = _Repo.GetItem(Id);
Assert.Equal(exp, myres);
});
}, findshim);
var myres = _Repo.GetItem(Id);
In both the trials, I have tried mocking IMongoCollectionExtensions.FindAsync() but result (output of the method i want to unit test after setting up mock/fake) in both cases are null and when I tried below Assertion if the FindAsync() method of IMongoCollectionExtension has Happened or not, but it didn't hit. I dont understand when the method i want to unit test is pointing to IMongoCollectionExtension.FindAsync() only but it is not hitting.
fakeIMongoCollExt.CallsTo(x => x.FindAsync(A<IMongoCollection<MyClass>>.Ignored, A<FilterDefinition<MyClass>>.Ignored, null, CancellationToken.None)).MustHaveHappened();
(Method signature has MongoCollections as first parameter - Extension Method) is showing that it didn't hit that method.
So I tried checking MustHaveHappened() for IMongoCollection.FindAsync() (It is interface method not the static class method which we are discussing above) which also tells that "The target of this call is not the fake object being configured."
I am not sure how FindAsync() is pointing. How to proceed with unit test cases. Please let me know if you have any idea.. Thanks in Advance..