我最近在我的一个房产安装人员的单元测试中遇到了一个小问题。我想设置我的属性以返回一个特定的值,并且不调用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);
}
}
测试结果的差异是由配置的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);
希望能帮助到你。