mongodb 单元测试MongoWriteExceptions

balp4ylt  于 2023-06-05  发布在  Go
关注(0)|答案(4)|浏览(485)

我想使用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类有一个内部构造函数

wfsdck30

wfsdck301#

一个基于驱动程序自己的测试的小示例,但是使用反射来获取内部构造函数

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的构造函数,它可能有类似的味道。

bfnvny8b

bfnvny8b2#

你可以使用反射创建一个具有内部构造函数的类的对象。
就像

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

上述代码中的第二个参数是指定Activator来查找非公共默认构造函数。
但这样就不能初始化任何值或使用参数化构造函数。
我假设你已经为mogo DB库创建了一个假的程序集,并使用shim来模拟UpdateOne方法。
如果是这种情况,您可以Shim WriteError对象,并使属性“Category”根据测试用例返回您想要任何值。
就像是

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

在上述代码中,语法可以不同。但想法是一样的

woobm2wo

woobm2wo3#

所以我在这里引用了@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") });
    }

编辑:对于我们这些不太熟悉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;
daolsyd0

daolsyd04#

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略有变化,这些是您需要传入以进行反射的最新对象

相关问题