模拟MongoCollection崩溃 - 调用目标抛出了异常

时间:2014-01-15 21:29:55

标签: c# mongodb nunit moq mongodb-.net-driver

我使用Moq模拟GetCollection方法,但线路崩溃。

var collectionSettings = new MongoCollectionSettings
{
    GuidRepresentation = GuidRepresentation.Standard,
    ReadEncoding = new UTF8Encoding(),
    ReadPreference = new ReadPreference(),
    WriteConcern = new WriteConcern(),
    WriteEncoding = new UTF8Encoding()
};

var collection = new Mock<MongoCollection<BsonDocument>>(database.Object, "MyCollection", collectionSettings);

//crashing here without any error dumped
database.Setup(f => f.GetCollection("MyCollection", collectionSettings)).Returns(collection.Object);

这是我得到的错误

Exception of type 'System.ArgumentOutOfRangeException' was thrown.
Parameter name: name
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark)
   at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at System.Activator.CreateInstance(Type type, Object[] args)
   at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance(Type proxyType, List`1 proxyArguments, Type classToProxy, Object[] constructorArguments)
   at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors)
   at Moq.Proxy.CastleProxyFactory.CreateProxy(Type mockType, ICallInterceptor interceptor, Type[] interfaces, Object[] arguments)
   at Moq.Mock`1.<InitializeInstance>b__0()
   at Moq.PexProtector.Invoke(Action action)
   at Moq.Mock`1.InitializeInstance()
   at Moq.Mock`1.OnGetObject()
   at Moq.Mock.GetObject()
   at Moq.Mock.get_Object()
   at Moq.Mock`1.get_Object()

有关热修复的想法吗?

2 个答案:

答案 0 :(得分:3)

接受的答案对C#驱动程序版本1.9.1不起作用,并使用OP引入的一些未公开类型。我已经改变了允许模拟MongoCollection<T>

的辅助方法
public static class MongoMock
{
    public static Mock<MongoServer> CreateMongoServer()
    {
        var serverSettings = new MongoServerSettings
        {
            Servers = new List<MongoServerAddress>
            {
                new MongoServerAddress("MockServer")
            }
        };

        var server = new Mock<MongoServer>(MockBehavior.Strict, serverSettings);

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

        return server;
    }

    public static Mock<MongoDatabase> CreateMongoDatabase(MongoServer server)
    {
        var databaseSettings = new MongoDatabaseSettings
        {
            GuidRepresentation = GuidRepresentation.Standard,
            ReadEncoding = new UTF8Encoding(),
            ReadPreference = new ReadPreference(),
            WriteConcern = new WriteConcern(),
            WriteEncoding = new UTF8Encoding()
        };
        var database = new Mock<MongoDatabase>(MockBehavior.Strict, server, "MockDatabase", databaseSettings);

        string message;
        database.Setup(db => db.Server).Returns(server);
        database.Setup(db => db.Settings).Returns(databaseSettings);
        database.Setup(db => db.IsCollectionNameValid(It.IsAny<string>(), out message)).Returns(true);

        return database;
    }

    public static Mock<MongoCollection<T>> CreateMongoCollection<T>(MongoDatabase database, string collectionName)
    {
        var collectionSetting = new MongoCollectionSettings();
        var collectionMock = new Mock<MongoCollection<T>>(MockBehavior.Strict, database, collectionName, collectionSetting);
        collectionMock.Setup(x => x.Database).Returns(database);
        collectionMock.Setup(x => x.Settings).Returns(collectionSetting);
        return collectionMock;
    }

    public static Mock<MongoCollection<T>> CreateMongoCollection<T>(string collectionName)
    {
        var server = CreateMongoServer().Object;
        var database = CreateMongoDatabase(server);
        return CreateMongoCollection<T>(database.Object, collectionName);
    }

    public static Mock<MongoCursor<T>> CreateMongoCursor<T>(MongoCollection<T> collection, IEnumerable<T> items = null)
    {
        var cursorMock = new Mock<MongoCursor<T>>(MockBehavior.Strict, collection, null, null, null, null);

        if (items != null)
        {
            cursorMock.Setup(c => c.GetEnumerator()).Returns(items.GetEnumerator());
        }

        return cursorMock;
    }
}

用法:

var serverMock = MongoMock.CreateMongoServer();
var server = serverMock.Object;

var databaseMock = MongoMock.CreateMongoDatabase(serverMock.Object);
var database = databaseMock.Object;

var collectionMock = MongoMock.CreateMongoCollection<BsonDocument>(databaseMock.Object, "FooCollection");
var collection = collectionMock.Object;

var cursorMock = MongoMock.CreateMongoCursor(collectionMock.Object, new List<BsonDocument>());
var cursor = cursorMock.Object;

答案 1 :(得分:2)

在阅读完源代码后,我发现我错过了一些要模拟的属性或方法。

以下是工作代码:

public MongoServer GetMockedMongoDbServer()
{
    var serverSettings = new MongoServerSettings
    {
        Servers = new List<MongoServerAddress>
        {
            new MongoServerAddress("unittest")
        }
    };
    var server = new MongoServer(serverSettings);
    return server;
}

public static Mock<MongoCollection<T>> CreateMockCollection<T>(MongoDatabase database, string name)
{
    var collectionSetting = new MongoCollectionSettings();
    var m = new Mock<MongoCollection<T>>(database, name, collectionSetting);
    m.Setup(x => x.Database).Returns(database);
    m.Setup(x => x.Settings).Returns(collectionSetting);
    return m;
}

public MongoDatabase GetMockedMongoDb(MongoServer server)
{
    var databaseSettings = new MongoDatabaseSettings()
    {
        GuidRepresentation = GuidRepresentation.Standard,
        ReadEncoding = new UTF8Encoding(),
        ReadPreference = new ReadPreference(),
        WriteConcern = new WriteConcern(),
        WriteEncoding = new UTF8Encoding()
    };

    var database = new Mock<MongoDatabase>(server, "db_name", databaseSettings);

    var message = String.Empty;

    //need to mock the following stuff
    database.Setup(db => db.Settings).Returns(databaseSettings);
    database.Setup(db => db.IsCollectionNameValid(It.IsAny<string>(), out message)).Returns(true);

    //mock the collection
    var c = CreateMockCollection(database.Object, "MyCollectionName");
    database.Setup(f => f.GetCollection("MyCollectionName")).Returns(c.Object);

    return database.Object;
}

public IMongoDbContext GetMockedMongoContext()
{
    var server = GetMockedMongoDbServer();
    var database = GetMockedMongoDb(server);

    var mongoDbContext = new Mock<IMongoDbContext>();
    mongoDbContext.Setup(x => x.GetMongoDatabase()).Returns(database);

    return mongoDbContext.Object;
}