I'm trying to write unit tests for my .NET Core API's service layer with NUnit and FakeItEasy and I have troubles with faking the connection to Mongo. The service is from the Microsoft documentation with small changes.
Here is my code:
IBaseService.cs
public interface IBaseService<T>
{
public IMongoClient MongoClient { get; }
public IMongoDatabase MongoDb { get; }
public IMongoCollection<T> GetCollection();
}
IBoxService.cs defines some functions
public interface IBoxService : IBaseService<Box>
BoxService.cs
public class BoxService : IBoxService
{
private readonly IOptions<DbSettings> _dbSettings;
private readonly IMongoCollection<Box> _boxCollection;
public BoxService(IOptions<DbSettings> dbSettings)
{
_dbSettings = dbSettings;
MongoClient = new MongoClient(_dbSettings.Value.ConnectionString);
MongoDb = MongoClient.GetDatabase(_dbSettings.Value.DatabaseName);
_boxCollection = GetCollection();
}
public IMongoClient MongoClient { get; }
public IMongoDatabase MongoDb { get; }
public IMongoCollection<Box> GetCollection()
{
return MongoDb.GetCollection<Box>(_dbSettings.Value.BoxCollectionName);
}
public async Task<List<Box>> FindAllAsync() =>
await _boxCollection.Find(_ => true).ToListAsync();
}
DbSettings.cs
public class DbSettings
{
public string ConnectionString { get; set; } = null!;
public string DatabaseName { get; set; } = null!;
public string BoxCollectionName { get; set; } = null!;
}
And finally the BoxServiceTest.cs
public class BoxServiceTest
{
private readonly IOptions<DbSettings> _fakeOptions;
private readonly IMongoClient _mongoClient;
private readonly IMongoDatabase _mongoDb;
private readonly IMongoCollection<Box> _boxCollection;
private readonly List<Box> _boxes;
public BoxServiceTest()
{
_boxCollection = A.Fake<IMongoCollection<Box>>();
_fakeOptions = A.Fake<IOptions<DbSettings>>();
_mongoClient = A.Fake<MongoClient>();
_mongoDb = A.Fake<IMongoDatabase>();
_boxes = new List<Box> {...};
}
[Test]
public async Task FindAllAsync_ReturnsAllBoxes()
{
// Arrange
var dbSettings = new DbSettings
{
ConnectionString = "mongodb://localhost:27017",
DatabaseName = "database",
BoxCollectionName = "boxes"
};
A.CallTo(() => _fakeOptions.Value).Returns(dbSettings);
var boxService = new BoxService(_fakeOptions);
// Act
var boxes = await boxService.FindAllAsync();
// Assert
}
}
Here the boxes contains the records from Mongo but I'd like it to have the values from the _boxes list instead of querying the db for every test.
I've tried faking some calls but without any success. Trying to fake the GetDatabase call:
A.CallTo(() => _mongoClient.GetDatabase(A<string>._, default)).Returns(_mongoDb);
But it gives an error:
The current proxy generator can not intercept the method MongoDB.Driver.IMongoClient.GetDatabase(System.String name, MongoDB.Driver.MongoDatabaseSettings settings) for the following reason: - Non-virtual members can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.
What am I doing wrong? How should I fake the Mongo connection and the returned list?