最近,在对我的一位资产设定者进行单元测试时,我有些头疼。我想将属性设置为返回某个值,并且不调用设置器逻辑,因为其中存在大量繁琐的操作,并且我不希望该逻辑影响我的单元测试。
我知道我可以将逻辑移到方法上,然后模拟该新方法,但是这个问题使我感到好奇,并且我已经做了一些工作。 我的研究结果在下面的FooTests类中,其中之一使用SetupProperty起作用,但让我感到这不是此方法的目的。
在Moq中,是否有一种专门的方法可以使Sets短路?
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);
}
}
答案 0 :(得分:1)
测试结果的差异是由配置的Mock的不同行为引起的。方法Setup
在第一个测试中,只需重写getter方法:
指定用于调用值返回方法的模拟类型的设置。
因此,在这种情况下,在构造函数中调用FooBar
会影响MagicNumber
。您在第二次测试中使用的方法SetupSet
的重载已过时,并且看起来它没有覆盖setter,只是建立了一个期望值,您以后可以验证吗?或添加回调:
在模拟类型上指定用于调用属性设置器的设置,而不管其值如何。
在这种情况下,构造函数中的FooBar
也会影响MagicNumber
。但是FooBar
的setter被调用了两次:从构造函数和lambda调用,在此它返回的返回值It.IsAny<int>
为0。最后,第三个测试的SetupProperty
设置了默认属性行为:
指定给定属性应具有
property behavior
,这意味着设置其值将导致该属性被保存并在请求该属性时返回(也称为存根)
因此,构造函数中的FooBar不会在第三个测试中影响MagicNumber
,因为整个属性都被存根覆盖了,而且您再也不会遇到FooBar
setter了。因此,第三个测试是绿色的。我想您在第三次测试中实现的配置可以满足您的需求。您可以将其与第一个结合使用,以使FooBar
getter始终返回相同的值:
fooPartialMock.SetupProperty(x => x.FooBar).Setup(x => x.FooBar).Returns(fooBar);
希望有帮助。