I’m developing an API which communicates with MongoDB and I need to create some statistics from one collection. I have the following service:
public class BoxService : IBoxService
{
private readonly IMongoCollection<Box> _boxCollection;
public BoxService(IOptions<DbSettings> dbSettings, IMongoClient mongoClient)
{
var mongoDatabase = mongoClient.GetDatabase(dbSettings.Value.DatabaseName);
_boxCollection = mongoDatabase.GetCollection<Box>(dbSettings.Value.BoxCollectionName);
}
public async Task<List<BoxStatisticsDto>> GetBoxNumberStatisticsAsync()
{
var boxNumberStatisticsList = new List<BoxStatisticsDto>();
var results = await _boxCollection.AsQueryable()
.Select(box => new { box.WarehouseId, Content = box.Content ?? string.Empty })
.ToListAsync();
// More calculations with the results list
return boxNumberStatisticsList;
}
}
And the following test:
public class BoxServiceTest
{
private readonly IMongoCollection<Box> _boxCollection;
private readonly List<Box> _boxes;
private readonly IBoxService _boxService;
public BoxServiceTest()
{
_boxCollection = A.Fake<IMongoCollection<Box>>();
_boxes = new List<Box> {...};
var mockOptions = A.Fake<IOptions<DbSettings>>();
var mongoClient = A.Fake<IMongoClient>();
var mongoDb = A.Fake<IMongoDatabase>();
A.CallTo(() => mongoClient.GetDatabase(A<string>._, default)).Returns(mongoDb);
A.CallTo(() => mongoDb.GetCollection<Box>(A<string>._, default)).Returns(_boxCollection);
_boxService = new BoxService(mockOptions, mongoClient);
}
}
This is working so far, the BoxService is created with the fake parameters and I can test other functionalities of the service (FindAll, FindById, Create, etc.) but how can I test the GetBoxNumberStatisticsAsync function? I can’t fake the AsQueryable because it’s an extension method.
2
Answers
Here is what I ended up with. A base interface for all my services:
An abstract class to have a generic constructor:
An interface for my BoxService:
The service itself:
And finally the test:
I'm not a huge fan of making the
CollectionToListAsync
public, but nothing really worked for me here. I tried creating IQueryable and IEnumerable from my list and convert them to IMongoQueryable but no success. I also tried faking the IMongoQueryable but I couldn't execute the Select on it as it gave an error that the 'collectionNamespace' can't be null and the CollectionNamespace can't be faked, because it's a sealed class.As you’ve noted, you can’t fake an extension method. This question is asked every once in a while. For example, see Faking an Extension Method in a 3rd Party Library. There are a few approaches: