【问题标题】:Moq setup is not returning correct valueMoq 设置未返回正确的值
【发布时间】:2021-06-25 20:25:40
【问题描述】:

我查看了其他答案,但尚未找到任何帮助。也许我是误会了。 GetDocumentCount 模拟不起作用。

被测类:

public class DeleteDocument
{
    private readonly IMongoClient _mongoClient;

    public DeleteDocument(IMongoClient mongoClient)
    {
        this._mongoClient = mongoClient;
    }

    public override bool ProcessRequest(DeleteDocumentRequest request)
    {
        var docObjectIds = request.Ids.Select(ObjectId.Parse).ToArray();
        var documents = _mongoClient.GetDocumentsCollection(Constants.DATABASE);
        var documentCount = GetDocumentCount(documents, docObjectIds);
        
        if (documentCount != request.Ids.Length)
        {
            throw new ValidationException(-6, "The document count doesn't match");
        }
        
        ... more code here
        return true;
    }

    public virtual long GetDocumentCount(IMongoCollection<Document> docs, ObjectId[] objIds)
    {
        return docs.Find(x => objIds.Contains(x.Id)).CountDocuments();
    }
}

单元测试是遗留代码并且无法正常工作,我很难理解它是否真的正确地模拟了 MongoDb。我还没有找到很多很好的 MongoDb 模拟示例。这是完整的单元测试:

[TestMethod]
public void DeleteDocument_DocumentCountDoesNotMatch_ReturnsErrorCode()
{
    var mockIMongoCollection = new Mock<IMongoCollection<Document>>();
    var asyncCursor = new Mock<IAsyncCursor<Document>>();

    var docCollection = new[]
    {
        // this is the document to delete
        new Document
        {
            CreateDate = DateTime.UtcNow,
            Id = new ObjectId("6074d4da433ab6b5a731b82c"),
            IsActive = true
        }
    };

    mockIMongoCollection.Setup(collection => collection.FindSync(
            Builders<Document>.Filter.Empty,
            It.IsAny<FindOptions<Document>>(),
            default))
        .Returns(asyncCursor.Object);
    
    asyncCursor.SetupSequence(async => async.MoveNext(default))
        .Returns(true)
        .Returns(false);

    asyncCursor.SetupGet(async => async.Current)
        .Returns(docCollection);

    var mongoDatabaseMock = new Mock<IMongoDatabase>();
    mongoDatabaseMock.Setup(x => x.GetCollection<Document>(
            It.IsAny<string>(),
            It.IsAny<MongoCollectionSettings>()))
        .Returns(mockIMongoCollection.Object);

    var mongoClientMock = new Mock<IMongoClient>();
    mongoClientMock.Setup(x => x.GetDatabase(
            It.IsAny<string>(),
            It.IsAny<MongoDatabaseSettings>()))
        .Returns(mongoDatabaseMock.Object);

    var mockClass = new Mock<DeleteDocument>(mongoClientMock.Object) 
        { CallBase = true };
    mockClass.Setup(
            x => x.GetDocumentCount
            (It.IsAny<IMongoCollection<Document>>(),
                It.IsAny<ObjectId[]>()))
        .Returns(Convert.ToInt64(1));

    var ex = Assert.ThrowsException<ValidationException>(() => 
        new DeleteDocument(mongoClientMock.Object)
        .ProcessRequest(new DeleteDocumentRequest(null)
        {
            Ids = new[] { "6074d4da433ab6b5a731b82c" }
        }));

    Assert.AreEqual(-6, ex.Code);
}

【问题讨论】:

  • 您使用模拟的方式也很重要。
  • 如果你在测试DeleteDocument,你想模拟IMongoClient,而不是DeleteDocument
  • @sellotape 我已经更新了我的单元测试代码。我模拟了 IMongoClient,但不清楚 GetDocumentCount 是如何被覆盖的?

标签: c# unit-testing moq


【解决方案1】:

看来你创建了一个被测对象的模拟

//...

var mockClass = new Mock<DeleteDocument>(mongoClientMock.Object) { //<-- mocked instance
    CallBase = true 
};

//...

然后在进行测试时继续使用测试对象的另一个单独实例

//...

var ex = Assert.ThrowsException<ValidationException>(() => 
    new DeleteDocument(mongoClientMock.Object) //<-- new instance here
    .ProcessRequest(new DeleteDocumentRequest(null)
    {
        Ids = new[] { "6074d4da433ab6b5a731b82c" }
    }));

//...

由于您还想覆盖 GetDocumentCount 的行为,因此在进行测试时需要使用这种边缘情况下的模拟

[TestMethod]
public void DeleteDocument_DocumentCountDoesNotMatch_ReturnsErrorCode() {
    //Arrange

    //...omitted for brevity

    var mockClass = new Mock<DeleteDocument>(mongoClientMock.Object) {
        CallBase = true 
    };
    mockClass
        .Setup(x => x.GetDocumentCount(It.IsAny<IMongoCollection<Document>>(), It.IsAny<ObjectId[]>()))
        .Returns(Convert.ToInt64(99)); //<-- this need to not match request

    var request = new DeleteDocumentRequest(null) {
            Ids = new[] { "6074d4da433ab6b5a731b82c" }
    }

    //Act & 
    Action act = () => mockClass.Object.ProcessRequest(request);        

    //Assert
    ValidationException ex = Assert.ThrowsException<ValidationException>(act);
    Assert.AreEqual(-6, ex.Code);
}

【讨论】:

  • 感谢您花时间解释并提供示例
猜你喜欢
  • 2021-06-28
  • 2015-12-14
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
  • 2015-09-02
  • 1970-01-01
  • 2019-11-01
  • 2013-09-11
相关资源
最近更新 更多