2014-01-15 104 views
3

我使用Moq來模擬GetCollection方法,但行崩潰。Mocking MongoCollection崩潰 - 異常已被調用的目標拋出

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() 

的熱點來解決它的任何想法的錯誤?

+1

如果你使用一個try/catch,你能趕上任何錯誤?通常,這種失敗通常表示'GetCollection'不能被覆蓋。 – Tejs

+0

@Tejs噢。謝謝!這是錯誤'{「類型'System.ArgumentOutOfRangeException'的異常被拋出。\ r \ n參數名稱:name」}' – zsong

+1

這聽起來像'GetCollection',實際的方法定義,正在運行,或者它調用。我懷疑你的模擬是不夠的。 – Tejs

回答

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; 
} 
2

接受的答案並沒有爲C#驅動程序版本1.9.1工作,並使用由OP引入了一些未披露的類型。我已經改變了helper方法允許嘲諷一個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; 
+0

如何添加模擬收集數據? –

+0

@Usama通過在'collectionMock'上設置'Find()'來返回一個遊標(通過'MongoMock.CreateMongoCursor()'創建),在這裏你可以提供一個'IEnumerable ',它將被返回到調用'查找()'。 – CodeCaster

+2

你可以分享這個代碼完全工作模擬的要點或在這裏? –

相關問題