How would I use moq to test a MongoDB service layer?

懵懂的女人 提交于 2021-02-07 11:54:43

问题


I have a service layer between my app and the mongo database.

I'm trying to build a unit test using moq I'm quite new to moq so I started with what I thought would be a trivial test.

Code to test:

    public List<BsonDocument> GetAllSettings()
    {
        var collection = MongoDatabase.GetCollection<BsonDocument>("Settings");
        var query = from e in collection.AsQueryable()
                    select e;

        var settings = query.ToList();
        return settings;
    }

Where: Settings is a Collection MongoDatabase is a MongoDBDriver.MongoDatabase

I've tried this as my test:

    [Test()]
    public void GetAllSettingsTest()
    {
        //Arrange
        BsonDocument doc01 = new BsonDocument();
        BsonDocument doc02 = new BsonDocument();

        var mongoDatabase = new Mock<MongoDatabase>();
        var collection = new Mock<MongoCollection<BsonDocument>>();
        mongoDatabase.Setup(f => f.GetCollection(MongoCollection.Settings)).Returns(collection.Object);
        collection.Object.Insert(doc01);
        collection.Object.Insert(doc02);

        ILogger logger = new Logger();
        DatabaseClient.DatabaseClient target = new DatabaseClient.DatabaseClient(logger);
        target.MongoDatabase = mongoDatabase.Object;

        MongoCursor<BsonDocument> cursor = collection.Object.FindAllAs<BsonDocument>();

        List<BsonDocument> expected = cursor.ToList();
        List<BsonDocument> actual;

        //Act
        actual = target.GetAllSettings();

        //Assert
        Assert.AreEqual(expected, actual);
    }

I'm getting an error of "Could not find a parameterless constructor" at:

mongoDatabase.Setup(f => f.GetCollection(MongoCollections.Settings)).Returns(collection.Object);

The error refers to the MongoCollection object. I didn't think it had a constructor.

What can I do to get my test to run?


回答1:


this question is most probably related to: How do I mock MongoDB objects to test my data models?

Anyway, here is minimal Moq configuration required to mock

        var message = string.Empty;

        var serverSettings = new MongoServerSettings()
        {
            GuidRepresentation = MongoDB.Bson.GuidRepresentation.Standard,
            ReadEncoding = new UTF8Encoding(),
            ReadPreference = new ReadPreference(),
            WriteConcern = new WriteConcern(),
            WriteEncoding = new UTF8Encoding()
        };

        var server = new Mock<MongoServer>(serverSettings);
        server.Setup(s => s.Settings).Returns(serverSettings);
        server.Setup(s => s.IsDatabaseNameValid(It.IsAny<string>(), out message)).Returns(true);

        var databaseSettings = new MongoDatabaseSettings()
        {
            GuidRepresentation = MongoDB.Bson.GuidRepresentation.Standard,
            ReadEncoding = new UTF8Encoding(),
            ReadPreference = new ReadPreference(),
            WriteConcern = new WriteConcern(),
            WriteEncoding = new UTF8Encoding()
        };

        var database = new Mock<MongoDatabase>(server.Object, "test", databaseSettings);
        database.Setup(db => db.Settings).Returns(databaseSettings);
        database.Setup(db => db.IsCollectionNameValid(It.IsAny<string>(), out message)).Returns(true);

        var mockedCollection = collection.Object;

Anyway, as I mentioned in linked question, this might not be useful when any of inner-workings of MongoDriver change.




回答2:


I'm not familiar with the MongoDbDriver.MongoDatabase, but if it works like I think it does, then you can't mock it directly. You need to abstract the MongoDB access code, and mock that. That would be an actual unit test. e.g.

public interface IMongoDBRepository
{
   Collection<T> GetCollection<T>(string name) where T BsonDocument;
}

public class MongoDbRepository : IMongoDBRepository
{
   public Collection<T> GetCollection<T>(string name) 
     where T : BsonDocument
   {
      return MongoDatabase.GetCollection<BsonDocument>(name);
   }
}

Now, in your code, you inject an IMongoDBRepository (using whatever DI method you like) and your code would looks something like this:

private IMongoDBRepository _mongoDBRepository; //this gets injected
public List<BsonDocument> GetAllSettings()
{
    var collection = _mongoDBRepository.GetCollection<BsonDocument>("Settings");
    var query = from e in collection.AsQueryable()
                select e;

    var settings = query.ToList();
    return settings;
}

And finally your unit test:

[Test()]
public void GetAllSettingsTest()
{
    //Arrange
    BsonDocument doc01 = new BsonDocument();
    BsonDocument doc02 = new BsonDocument();

    var mongoDatabase = new Mock<IMongoDBRepository>();
    var collection = new Mock<MongoCollection<BsonDocument>>();
    mongoDatabase.Setup(f => f.GetCollection(MongoCollection.Settings)).Returns(collection.Object);
    collection.Object.Insert(doc01);
    collection.Object.Insert(doc02);

   //rest of test
}


来源:https://stackoverflow.com/questions/13257198/how-would-i-use-moq-to-test-a-mongodb-service-layer

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!