问题
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