Я хочу протестировать свою обработку исключения MongoWriteException с помощью драйвера Mongo, вот пример метода:

    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 есть внутренний конструктор

2
Mark Walsh 8 Сен 2016 в 15:38

3 ответа

Лучший ответ

Небольшой пример, основанный на собственные тесты драйвера, но с использованием отражения для доступа к внутренним конструкторам

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, который может иметь похожий запах.

5
logan rakai 14 Сен 2016 в 18:30

Вы можете создать объект класса с помощью внутреннего конструктора, используя отражение.

Что-то типа

 var obj = Activator.CreateInstance(typeof(WriteError), true);

Вы можете создать объект класса с помощью внутреннего конструктора, используя отражение.…

Но таким образом вы не можете инициализировать какие-либо значения или использовать конструкторы с параметром.

Я предполагаю, что вы создали поддельную сборку для библиотеки mogo DB и использовали прокладку для имитации метода UpdateOne.

В этом случае вы можете установить Shim для объекта WriteError и сделать так, чтобы свойство «Категория» возвращало любое желаемое значение в соответствии с тестовым примером.

Это было бы что-то вроде

ShimsWriteError.AllInstances.Category = errorObj => ServerErrorCategory.DuplicateKey

В приведенном выше коде синтаксис может отличаться. но идея та же.

0
Binu Vijayan 14 Сен 2016 в 17:17

Поэтому я взял здесь ответ @logan rakai (https://stackoverflow.com/a/39497316/1001408) и изменил его немного. Вот что у меня получилось.

    [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") });
    }
0
Community 23 Май 2017 в 10:33