单元测试 MongoWriteExceptions
Unit testing MongoWriteExceptions
我想使用 Mongo 驱动程序测试我对 MongoWriteException 的处理,这里是一个示例方法:
private void Update()
{
try
{
var find = Builders<Filter>.Filter.Eq(e => e.Id, "someId");
var update = Builders<Filter>.Update.Set(e => e.SomeValue, "AValue");
_documentStore.MongoCollection<Filter>().UpdateOne(find, update, new UpdateOptions { IsUpsert = true }, CancellationToken.None);
}
catch (MongoWriteException mongoWriteException)
{
if (mongoWriteException.WriteError.Category != ServerErrorCategory.DuplicateKey)
{
throw;
}
}
}
有谁知道如何模拟 MongoWriteException?我试着像这样构造它:
var mongoWriteException = new MongoWriteException(new ConnectionId(new ServerId(new ClusterId(1), new DnsEndPoint("d", 2)), 0), new WriteError(), // <- Protected constructor
但是 WriteError class 有一个内部构造函数
您可以使用反射创建具有内部构造函数的 class 对象。
类似于
var obj = Activator.CreateInstance(typeof(WriteError), true);
上面代码中的第二个参数是指定Activator寻找非public默认构造函数。
但是这样你就不能初始化任何值或使用带参数的构造函数。
我假设您已经为 mogo DB 库创建了一个假程序集,并使用 shim 来模拟 UpdateOne 方法。
如果是这种情况,您可以填充 WriteError 对象并根据测试用例使 属性 "Category" return 任何您想要的值。
它会像
ShimsWriteError.AllInstances.Category = errorObj => ServerErrorCategory.DuplicateKey
上述代码中的语法可能不同。但想法是一样的。
基于the driver's own tests但使用反射获取内部构造函数的小示例
static class MockMongoCollection // : IMongoCollection<TDocument>
{
private static readonly MongoWriteException __writeException;
static MockMongoCollection()
{
var connectionId = new ConnectionId(new ServerId(new ClusterId(1), new DnsEndPoint("localhost", 27017)), 2);
var innerException = new Exception("inner");
var ctor = typeof (WriteConcernError).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
var writeConcernError = (WriteConcernError)ctor.Invoke(new object[] { 1, "writeConcernError", new BsonDocument("details", "writeConcernError") });
ctor = typeof (WriteError).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
var writeError = (WriteError) ctor.Invoke(new object[] {ServerErrorCategory.Uncategorized, 1, "writeError", new BsonDocument("details", "writeError")});
__writeException = new MongoWriteException(connectionId, writeError, writeConcernError, innerException);
}
public static void UpdateOne()
{
throw __writeException;
}
}
class ExampleTests
{
[Test]
public void UncategorizedWriteExceptionTest()
{
Assert.Throws<MongoWriteException>(MockMongoCollection.UpdateOne);
}
}
还有一个使用 SerializationInfo 的构造函数可能有类似的味道。
所以我在这里采纳了@logan rakai 的回答 () 并做了一些修改。这是我最终得到的结果。
[Test]
public void GivenADuplicateKeyWriteErrorOccurs_WhenCallingUpdateOne_ThenNoExceptionIsThrown()
{
// Given
var someMongoService = CreateSomeObject();
_mockMongoCollection.Setup(x => x.UpdateOne(It.IsAny<FilterDefinition<SomeObject>>(), It.IsAny<UpdateDefinition<SomeObject>>(), It.IsAny<UpdateOptions>(), default(CancellationToken))).Throws(CreateMongoWriteException(ServerErrorCategory.DuplicateKey));
// When / Then
Assert.DoesNotThrow(() => someMongoService.Upsert(new CreateNewSomeObject());
}
[Test]
public void GivenAExceptionOccursWhichIsNotADuplicateKeyWriteError_WhenCallingUpdateOne_ThenTheExceptionIsThrown()
{
// Given
var someMongoService = CreateFilterService();
var exception = CreateMongoWriteException(ServerErrorCategory.ExecutionTimeout);
_mockMongoCollection.Setup(x => x.UpdateOne(It.IsAny<FilterDefinition<SomeObject>>(), It.IsAny<UpdateDefinition<SomeObject>>(), It.IsAny<UpdateOptions>(), default(CancellationToken))).Throws(exception);
// When / Then
Assert.Throws<MongoWriteException>(() => someMongoService.Upsert(new CreateNewSomeObject());
}
public static MongoWriteException CreateMongoWriteException(ServerErrorCategory serverErrorCategory)
{
var connectionId = new ConnectionId(new ServerId(new ClusterId(1), new DnsEndPoint("localhost", 27017)), 2);
var writeConcernError = CreateWriteConcernError();
var writeError = CreateWriteError(serverErrorCategory);
return new MongoWriteException(connectionId, writeError, writeConcernError, new Exception());
}
private static WriteError CreateWriteError(ServerErrorCategory serverErrorCategory)
{
var ctor = typeof (WriteError).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
var writeError = (WriteError)ctor.Invoke(new object[] {serverErrorCategory, 1, "writeError", new BsonDocument("details", "writeError")});
return writeError;
}
private static WriteConcernError CreateWriteConcernError()
{
var ctor = typeof(WriteConcernError).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
return (WriteConcernError)ctor.Invoke(new object[] { 1, "writeConcernError", new BsonDocument("details", "writeConcernError") });
}
编辑:这里是我们这些使用较少 IDE 的人所需要的命名空间
using System;
using System.Net;
using System.Reflection;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Core.Clusters;
using MongoDB.Driver.Core.Connections;
using MongoDB.Driver.Core.Servers;
我想使用 Mongo 驱动程序测试我对 MongoWriteException 的处理,这里是一个示例方法:
private void Update()
{
try
{
var find = Builders<Filter>.Filter.Eq(e => e.Id, "someId");
var update = Builders<Filter>.Update.Set(e => e.SomeValue, "AValue");
_documentStore.MongoCollection<Filter>().UpdateOne(find, update, new UpdateOptions { IsUpsert = true }, CancellationToken.None);
}
catch (MongoWriteException mongoWriteException)
{
if (mongoWriteException.WriteError.Category != ServerErrorCategory.DuplicateKey)
{
throw;
}
}
}
有谁知道如何模拟 MongoWriteException?我试着像这样构造它:
var mongoWriteException = new MongoWriteException(new ConnectionId(new ServerId(new ClusterId(1), new DnsEndPoint("d", 2)), 0), new WriteError(), // <- Protected constructor
但是 WriteError class 有一个内部构造函数
您可以使用反射创建具有内部构造函数的 class 对象。
类似于
var obj = Activator.CreateInstance(typeof(WriteError), true);
上面代码中的第二个参数是指定Activator寻找非public默认构造函数。
但是这样你就不能初始化任何值或使用带参数的构造函数。
我假设您已经为 mogo DB 库创建了一个假程序集,并使用 shim 来模拟 UpdateOne 方法。
如果是这种情况,您可以填充 WriteError 对象并根据测试用例使 属性 "Category" return 任何您想要的值。
它会像
ShimsWriteError.AllInstances.Category = errorObj => ServerErrorCategory.DuplicateKey
上述代码中的语法可能不同。但想法是一样的。
基于the driver's own tests但使用反射获取内部构造函数的小示例
static class MockMongoCollection // : IMongoCollection<TDocument>
{
private static readonly MongoWriteException __writeException;
static MockMongoCollection()
{
var connectionId = new ConnectionId(new ServerId(new ClusterId(1), new DnsEndPoint("localhost", 27017)), 2);
var innerException = new Exception("inner");
var ctor = typeof (WriteConcernError).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
var writeConcernError = (WriteConcernError)ctor.Invoke(new object[] { 1, "writeConcernError", new BsonDocument("details", "writeConcernError") });
ctor = typeof (WriteError).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
var writeError = (WriteError) ctor.Invoke(new object[] {ServerErrorCategory.Uncategorized, 1, "writeError", new BsonDocument("details", "writeError")});
__writeException = new MongoWriteException(connectionId, writeError, writeConcernError, innerException);
}
public static void UpdateOne()
{
throw __writeException;
}
}
class ExampleTests
{
[Test]
public void UncategorizedWriteExceptionTest()
{
Assert.Throws<MongoWriteException>(MockMongoCollection.UpdateOne);
}
}
还有一个使用 SerializationInfo 的构造函数可能有类似的味道。
所以我在这里采纳了@logan rakai 的回答 (
[Test]
public void GivenADuplicateKeyWriteErrorOccurs_WhenCallingUpdateOne_ThenNoExceptionIsThrown()
{
// Given
var someMongoService = CreateSomeObject();
_mockMongoCollection.Setup(x => x.UpdateOne(It.IsAny<FilterDefinition<SomeObject>>(), It.IsAny<UpdateDefinition<SomeObject>>(), It.IsAny<UpdateOptions>(), default(CancellationToken))).Throws(CreateMongoWriteException(ServerErrorCategory.DuplicateKey));
// When / Then
Assert.DoesNotThrow(() => someMongoService.Upsert(new CreateNewSomeObject());
}
[Test]
public void GivenAExceptionOccursWhichIsNotADuplicateKeyWriteError_WhenCallingUpdateOne_ThenTheExceptionIsThrown()
{
// Given
var someMongoService = CreateFilterService();
var exception = CreateMongoWriteException(ServerErrorCategory.ExecutionTimeout);
_mockMongoCollection.Setup(x => x.UpdateOne(It.IsAny<FilterDefinition<SomeObject>>(), It.IsAny<UpdateDefinition<SomeObject>>(), It.IsAny<UpdateOptions>(), default(CancellationToken))).Throws(exception);
// When / Then
Assert.Throws<MongoWriteException>(() => someMongoService.Upsert(new CreateNewSomeObject());
}
public static MongoWriteException CreateMongoWriteException(ServerErrorCategory serverErrorCategory)
{
var connectionId = new ConnectionId(new ServerId(new ClusterId(1), new DnsEndPoint("localhost", 27017)), 2);
var writeConcernError = CreateWriteConcernError();
var writeError = CreateWriteError(serverErrorCategory);
return new MongoWriteException(connectionId, writeError, writeConcernError, new Exception());
}
private static WriteError CreateWriteError(ServerErrorCategory serverErrorCategory)
{
var ctor = typeof (WriteError).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
var writeError = (WriteError)ctor.Invoke(new object[] {serverErrorCategory, 1, "writeError", new BsonDocument("details", "writeError")});
return writeError;
}
private static WriteConcernError CreateWriteConcernError()
{
var ctor = typeof(WriteConcernError).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
return (WriteConcernError)ctor.Invoke(new object[] { 1, "writeConcernError", new BsonDocument("details", "writeConcernError") });
}
编辑:这里是我们这些使用较少 IDE 的人所需要的命名空间
using System;
using System.Net;
using System.Reflection;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Core.Clusters;
using MongoDB.Driver.Core.Connections;
using MongoDB.Driver.Core.Servers;