如何在Moq中短路调用属性setter

问题描述 投票:1回答:1

我最近在我的一个房产安装人员的单元测试中遇到了一个小问题。我想设置我的属性以返回一个特定的值,并且不调用setter逻辑,因为它在那里有一些繁重的操作,我不希望这个逻辑影响我的单元测试。

我知道我可以将这个逻辑移到一个方法然后嘲笑那个新方法,但这个问题让我好奇,我挖了一点。我的研究结果在下面的FooTests类中,其中一个使用SetupProperty工作,但让我觉得这不是这个方法的编写方式。

是否有专门的方法来在Moq的部分模拟中短路设置器?

Foo.cs:

public class Foo
{
    private int _bar;
    public virtual int Bar
    {
        get => _bar;
        set
        {
            MagicNumber+=FooBar;
            _bar = value;
        } 
    }

    private int _fooBar;
    public virtual int FooBar
    {
        get => _fooBar;
        set
        {
            //Complex and heavy logic that makes the magic number -value
            MagicNumber = -value;
            _fooBar = value;
        }
    }

    public int MagicNumber { get; set; }

    public Foo()
    {
        FooBar = 1;
    }
}

FooTests.cs:

[TestFixture]
public class FooTests
{
    //Using ordinary setup.
    [TestCase(1, 2, 2, TestName = "BarSetter_BarSetToOneAndFooBarEqualsTwo_MagicNumberEqualsTwo")]
    public void BarSetterTest(int bar, int fooBar, int expectedMagicNumber)
    {
        var fooPartialMock = new Mock<Foo> {CallBase = true};
        fooPartialMock.Setup(x => x.FooBar).Returns(fooBar);
        fooPartialMock.Object.Bar = bar;
        Assert.AreEqual(expectedMagicNumber, fooPartialMock.Object.MagicNumber);
    }

    //Using callbacks.
    [TestCase(1, 2, 2, TestName = "BarSetter_BarSetToOneAndFooBarEqualsTwo_MagicNumberEqualsTwo2")]
    public void BarSetterTest2(int bar, int fooBar, int expectedMagicNumber)
    {
        var fooPartialMock = new Mock<Foo> { CallBase = true };
        fooPartialMock.SetupSet(x => x.FooBar = It.IsAny<int>()).Callback<int>(x => {});
        fooPartialMock.Object.Bar = bar;
        Assert.AreEqual(expectedMagicNumber, fooPartialMock.Object.MagicNumber);
    }

    //Using SetupProperty.
    [TestCase(1, 2, 2, TestName = "BarSetter_BarSetToOneAndFooBarEqualsTwo_MagicNumberEqualsTwo3")]
    public void BarSetterTest3(int bar, int fooBar, int expectedMagicNumber)
    {
        var fooPartialMock = new Mock<Foo> { CallBase = true };
        fooPartialMock.SetupProperty(x => x.FooBar);
        fooPartialMock.Object.FooBar = fooBar;
        fooPartialMock.Object.Bar = bar;
        Assert.AreEqual(expectedMagicNumber, fooPartialMock.Object.MagicNumber);
    }
}
c# unit-testing nunit moq
1个回答
1
投票

测试结果的差异是由配置的Mock的不同行为引起的。方法Setup在第一个测试中只是覆盖getter方法:

指定模拟类型的设置,以调用值返回方法。

所以在这种情况下,FooBar在构造函数中的调用会影响MagicNumber。你在第二次测试中使用的方法SetupSet的重载是过时的,看起来它不会覆盖setter,它只是设置了一个期望,你可以稍后验证? on或添加回调:

指定对模拟类型的设置,以调用属性setter,无论其值如何。

在这种情况下,构造函数中的FooBar也会影响MagicNumber。然而,FooBar setter被调用两次:来自构造函数和lambda,它使用It.IsAny<int>的返回值调用,它是0.最后,来自第三个测试的SetupProperty设置默认属性行为:

指定给定属性应该具有property behavior,这意味着设置其值将导致它被保存并在以后请求属性时返回(这也称为存根)

所以构造函数中的FooBar在第三次测试中不影响MagicNumber,因为整个属性都用stub来覆盖,你永远不会得到FooBar setter。因此第三次测试是绿色的。我想您在第三次测试中实现的配置可以满足您的需求。您可以将它与第一个结合使FooBar getter始终返回相同的值:

fooPartialMock.SetupProperty(x => x.FooBar).Setup(x => x.FooBar).Returns(fooBar);

希望能帮助到你。

© www.soinside.com 2019 - 2024. All rights reserved.