Reputation: 3361
I want to test my handling of a MongoWriteException using the Mongo driver, here is a sample method:
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;
}
}
}
Does anyone know how I can mock a MongoWriteException? I tried to construct it like so:
var mongoWriteException = new MongoWriteException(new ConnectionId(new ServerId(new ClusterId(1), new DnsEndPoint("d", 2)), 0), new WriteError(), // <- Protected constructor
But the WriteError class has an internal constructor
Upvotes: 4
Views: 2775
Reputation: 143
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", "writeConcernError", new BsonDocument("details", "writeConcernError"), new List<string>() });
ctor = typeof(WriteError).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
var writeError = (WriteError)ctor.Invoke(new object[] { ServerErrorCategory.Uncategorized, 1, "writeError", new BsonDocument("details", "writeError") });
var exception = new MongoWriteException(connectionId, writeError, writeConcernError, innerException);
logan rakai's answer has changed slightly and these are the latest objects you'll need to pass in for reflection
Upvotes: 1
Reputation: 3361
So I took @logan rakai's answer here (https://stackoverflow.com/a/39497316/1001408) and changed it a bit. Here is what I ended up with.
[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") });
}
Edit: And here are the required namespaces for those of us with lesser IDEs
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;
Upvotes: 0
Reputation: 2557
A small example based on the driver's own tests but using reflection to get to the internal constructors
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);
}
}
There is also a constructor using SerializationInfo which may have a similar smell.
Upvotes: 11
Reputation: 803
You can create the object of a class with Internal constructor using reflection.
Something like
var obj = Activator.CreateInstance(typeof(WriteError), true);
The second parameter in the above code is to specify the Activator to look for non public default constructors.
But this way you cannot initialize any values or use Parametered constructors.
I am assuming you have created a fake assembly for mogo DB library and using shim to mock the UpdateOne method.
if that the case, you can Shim the WriteError object and make the property "Category" return any value you desire according to the test case.
It would be something like
ShimsWriteError.AllInstances.Category = errorObj => ServerErrorCategory.DuplicateKey
The syntax may be different in the above code. but the idea is same.
Upvotes: 0