起订量验证方法不适用于 ToList

发布于 2025-01-11 07:45:48 字数 1366 浏览 3 评论 0 原文

我对 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() 方法。为什么会这样?

I am fairly new to unit testing in C# and learning to use Moq. Below is the example of my problem with Moq Verify() method.

[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());
}

The above scenerio works, but when I remove someList variable and use ToList() directly in Verify(), like this:

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

then I get the following exception:

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"])

As one could imagine, this is quite problematic, what if someMethod() would accept many collection-type parameters? For this particular example I would have to create many variables to pass to Verify() method. Why does it work this way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

青瓷清茶倾城歌 2025-01-18 07:45:48

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

为了克服这个问题,您需要在 Verify 中使用 It.Is

problematicMock.Verify(
    x => x.someMethod(
       It.Is<List<string>>(input => AssertCollection(stringCollection.ToList(), input))), 
    Times.Once());
  • It.Is 接收 Func ;, 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() 那么它将失败。

In short Moq compares List<T> instances on reference basis. The two ToList calls create two separate collections therefor their references are different.

In order to overcome of this you need to use It.Is inside your Verify

problematicMock.Verify(
    x => x.someMethod(
       It.Is<List<string>>(input => AssertCollection(stringCollection.ToList(), input))), 
    Times.Once());
  • It.Is receives a Func<List<string>, bool> delegate
  • input is the argument of the someMethod call

Here is a naive implementation of the AssertCollection:

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

If you pass stringCollection.ToList() as an expected value then it will pass, but if you pass
stringCollection.Reverse.ToList() or stringCollection.Skip(1).ToList() then it will fail.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文