Moq 验证方法不适用于 ToList

Moq Verify method not working with ToList

我对 C# 中的单元测试和学习使用 Moq 还很陌生。下面是我的 Moq Verify() 方法问题示例。

[Theory]
[AutoData]
public async Task WhenSomething_ThenSomething(IEnumerable<string> stringCollection)
{
        //Arange
        //Mock of the method used in Handle() that returns stringCollection.
        someMock.Setup(x => x.MethodReturningStringCollectionForHandler()).ReturnsAsync(stringCollection);
        var someList = stringCollection.ToList();

        //Act
        await handler.Handle(new SomeRequest(someId));

        //Assert
        //I want to verify if someMethod() inside handler was called once but with appropriate stringCollection
        problematicMock.Verify(x => x.someMethod(someList), Times.Once());
}

上面的场景有效,但是当我删除 someList 变量并直接在 Verify() 中使用 ToList() 时,如下所示:

problematicMock.Verify(x => x.someMethod(stringCollection.ToList()), Times.Once());

然后我得到以下异常:

Message: 
    Moq.MockException : 
    Expected invocation on the mock once, but was 0 times: x => x.someMethod(["83436e1f-bd2f-44d3-9f8c-ba6afbf73e95", "16593c11-0959-4ebe-aafd-d5fbe0cfbd17", "633e6557-bed0-4ff0-b550-8790fab9e629"])

可想而知,这是一个很大的问题,如果someMethod()接受很多集合类型的参数呢?对于这个特定的例子,我将不得不创建许多变量来传递给 Verify() 方法。为什么会这样?

简而言之,Moq 在参考基础上比较 List<T> 个实例。这两个 ToList 调用创建了两个单独的集合,因此它们的引用不同。

为了克服这个问题,您需要在 Verify

中使用 It.Is
problematicMock.Verify(
    x => x.someMethod(
       It.Is<List<string>>(input => AssertCollection(stringCollection.ToList(), input))), 
    Times.Once());
  • It.Is 收到 Func<List<string>, bool> 代表
  • inputsomeMethod 调用的参数

这是 AssertCollection:

的简单实现
public static bool AssertCollection(List<string> expected, List<string> actual)
{
    try
    {
        Assert.Equal(expected, actual);
    }
    catch
    {
        return false;
    }
    return true;
}

如果您将 stringCollection.ToList() 作为预期值传递,那么它将通过,但如果您通过 stringCollection.Reverse.ToList()stringCollection.Skip(1).ToList() 那么它将失败。