简体   繁体   English

Moq 使用对象参数验证

[英]Moq verify with object parameter

I am trying to verify a parameter that is a class.我正在尝试验证作为类的参数。 The code being tested is fine.正在测试的代码很好。 The bug is in the test.该错误在测试中。

I have tried two methods, both of which have failed.我试过两种方法,都失败了。

Here are my attempts:这是我的尝试:

1: 1:

this.MockImageResizeFilter.Verify(m => m.Filter(this.UploadedFileData, new ImageFilterOptions()
    {
        Width = 256,
        Height = 256,
    }));

This always fails, even though an object passed as the second parameter has equal properties.这总是失败,即使作为第二个参数传递的对象具有相同的属性。 The first parameter is verified fine.第一个参数验证良好。

2: 2:

this.MockImageResizeFilter.Setup(m => m.Filter(It.IsAny<byte[]>(), It.IsAny<ImageFilterOptions>()))
    .Callback<byte[], ImageFilterOptions>((data, options) =>
        {
            Assert.AreEqual(this.UploadedFileData, data, "data");
            Assert.AreEqual(filterOptions.Width, options.Width, "Width");
            Assert.AreEqual(filterOptions.Height, options.Height, "Height");
        }
    );

This always passes, even when it should fail.这总是通过,即使它应该失败。 The Asserts in the callback do fail, but the exception is not passed to the outer context, and thus the test always passes.回调中的 Asserts 确实失败,但异常不会传递到外部上下文,因此测试总是通过。

Can you help me find what I am doing wrong?你能帮我找出我做错了什么吗?

The first attempt is closer to what you want to achieve. 第一次尝试更接近您想要实现的目标。

The reason it fails is that Moq (probably) uses Object.Equals under the cover to test if the ImageFilterOptions parameter that the method was called with is the same instance as the one you supplied in the call to Verify . 失败的原因是Moq(可能)使用封面下的Object.Equals来测试调用该方法的ImageFilterOptions参数是否与您在Verify调用中提供的实例相同。

It is impossible for them to be the same instance, because in Verify you create a new ImageFilterOptions() . 它们不可能是同一个实例,因为在Verify您创建了一个new ImageFilterOptions()

Instead of performing the parameter check this way, you could use Moq's It.Is syntax to provide an expression that verifies the parameter was the expected one. 您可以使用Moq的It.Is语法来提供验证参数是否为预期参数的表达式, It.Is这种方式执行参数检查。

In your case, you want to check that the parameter is of type ImageFilterOptions and that both the Width and the Height are set to 256 . 在您的情况下,您要检查参数是否为ImageFilterOptions类型,并且WidthHeight都设置为256 The expression that allows you to do that is: 允许您这样做的表达式是:

It.Is<ImageFilterOptions>(p => p.Width == 256 && p.Height == 256)

So, your call to Verify could look like this: 因此,您对Verify的调用可能如下所示:

this.MockImageResizeFilter.Verify(m => m.Filter(
            this.UploadedFileData,
            It.Is<ImageFilterOptions>(p => p.Width == 256 && p.Height == 256)));

Another way is to use the callback to save the argument to a variable and then assert against that:另一种方法是使用回调将参数保存到变量中,然后对其进行断言:

ImageFilterOptions passedOptions = null;
this.MockImageResizeFilter.Setup(m => m.Filter(It.IsAny<byte[]>(), It.IsAny<ImageFilterOptions>()))
    .Callback<byte[], ImageFilterOptions>((data, options) =>
    {
        passedOptions = options
    });

// <exercise the mocked object>

this.MockImageResizeFilter.Verify(m => m.Filter(this.UploadedFileData, It.IsAny<ImageFilterOptions>());
Assert.AreEqual(expectedOptions.Width, passedOptions.Width, "Width");
Assert.AreEqual(expectedOptions.Height, passedOptions.Height, "Height");

It's longer than the accepted answer but also more flexible.它比公认的答案更长,但也更灵活。 For instance, you get the opportunity to skip testing each property individually, which is nice when dealing with objects with many properties:例如,您有机会跳过单独测试每个属性,这在处理具有许多属性的对象时很好:

using FluentAssertions;

// ...

passedOptions.Should().BeEquivalentTo(expectedOptions);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM