如何在 Moq 中短路调用 属性 setter
How to short-circuit invocation of property setter in Moq
我最近在对我的 属性 setter 之一进行单元测试时有点头疼。我想将我的 属性 设置为 return 某个值并且不调用 setter 逻辑,因为它有一些繁重的操作,我不希望该逻辑影响我的单元测试.
我知道我可以将该逻辑移至一个方法,然后模拟该新方法,但这个问题让我很好奇,我已经深入了解了一些。
我的研究结果在下面的 FooTests class 中,其中一个使用 SetupProperty 有效,但让我觉得这不是编写此方法的目的。
在 Moq 的部分模拟中是否有专门的方法来短路 setters?
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);
}
}
测试结果的差异是由配置的模拟的不同行为造成的。方法 Setup
在第一个测试中只需重写 getter 方法:
Specifies a setup on the mocked type for a call to a value returning method.
所以在这种情况下,在构造函数中调用 FooBar
会影响 MagicNumber
。你在第二次测试中使用的方法 SetupSet
的重载已经过时,看起来它没有覆盖 setter,它只是建立了一个期望,你可以稍后验证?打开或添加回调:
Specifies a setup on the mocked type for a call to to a property setter, regardless of its value.
在这种情况下,构造函数中的 FooBar
也会影响 MagicNumber
。但是 FooBar
setter 被调用了两次:从构造函数和 lambda 调用,其中它使用 It.IsAny<int>
的 return 值调用,即 0。最后,SetupProperty
从第三个测试设置默认 属性 行为:
Specifies that given property should have a property behavior
, meaning that setting its value will cause it to be saved and later returned when the property is requested(this is also known as stubbing)
因此构造函数中的 FooBar 不会影响第三次测试中的 MagicNumber
,因为整个 属性 都被存根覆盖了,您永远不会到达 FooBar
setter.因此第三个测试是绿色的。我想您在第三次测试中实施的配置可以满足您的需求。您可以将它与第一个组合起来,使 FooBar
getter 总是 return 相同的值:
fooPartialMock.SetupProperty(x => x.FooBar).Setup(x => x.FooBar).Returns(fooBar);
希望对您有所帮助。
我最近在对我的 属性 setter 之一进行单元测试时有点头疼。我想将我的 属性 设置为 return 某个值并且不调用 setter 逻辑,因为它有一些繁重的操作,我不希望该逻辑影响我的单元测试.
我知道我可以将该逻辑移至一个方法,然后模拟该新方法,但这个问题让我很好奇,我已经深入了解了一些。 我的研究结果在下面的 FooTests class 中,其中一个使用 SetupProperty 有效,但让我觉得这不是编写此方法的目的。
在 Moq 的部分模拟中是否有专门的方法来短路 setters?
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);
}
}
测试结果的差异是由配置的模拟的不同行为造成的。方法 Setup
在第一个测试中只需重写 getter 方法:
Specifies a setup on the mocked type for a call to a value returning method.
所以在这种情况下,在构造函数中调用 FooBar
会影响 MagicNumber
。你在第二次测试中使用的方法 SetupSet
的重载已经过时,看起来它没有覆盖 setter,它只是建立了一个期望,你可以稍后验证?打开或添加回调:
Specifies a setup on the mocked type for a call to to a property setter, regardless of its value.
在这种情况下,构造函数中的 FooBar
也会影响 MagicNumber
。但是 FooBar
setter 被调用了两次:从构造函数和 lambda 调用,其中它使用 It.IsAny<int>
的 return 值调用,即 0。最后,SetupProperty
从第三个测试设置默认 属性 行为:
Specifies that given property should have a
property behavior
, meaning that setting its value will cause it to be saved and later returned when the property is requested(this is also known as stubbing)
因此构造函数中的 FooBar 不会影响第三次测试中的 MagicNumber
,因为整个 属性 都被存根覆盖了,您永远不会到达 FooBar
setter.因此第三个测试是绿色的。我想您在第三次测试中实施的配置可以满足您的需求。您可以将它与第一个组合起来,使 FooBar
getter 总是 return 相同的值:
fooPartialMock.SetupProperty(x => x.FooBar).Setup(x => x.FooBar).Returns(fooBar);
希望对您有所帮助。