属性上的Moq SetupSet

时间:2014-07-11 13:26:22

标签: moq

我正在尝试学习使用Moq(4)来测试下面的C#代码。我希望通过设置

mockTimer.SetupSet(m => m.Interval = It.IsInRange(
            interval - shorter, interval + longer, Range.Inclusive));

在调用为interval属性赋值的方法(ageService.AddParticipant方法)之前,测试将在分配不正确的值时抛出。但是,即使将指定范围之外的值分配给AddParticipant方法中的Interval属性,测试也会通过。我还发现timer.Interval在执行AddParticipant方法后的值为0,即使我在步进AddParticipant方法时可以看到此属性被赋予非零值。

[TestMethod]
public void TestAgeUpdatingStartOnAdd()
{
    var mockTimer = new Mock<IDispatcherTimer>();
    mockTimer.SetupProperty(m => m.Interval);
    mockTimer.Setup(m => m.Start());
    mockTimer.Setup(m => m.Stop());
    IDispatcherTimer timer = mockTimer.Object;

    var ageService = new AgeUpdatingService(timer);

    TimeSpan interval = TimeSpan.FromMinutes(10);
    TimeSpan tolerance = TimeSpan.FromMilliseconds(100)

    mockTimer.SetupSet(m => m.Interval = It.IsInRange(
        interval - tolerance, interval + tolerance, Range.Inclusive));
    ageService.AddParticipant(new Participant{ DOB = DateTime.Now + interval });

我做错了什么?我是否一起错过了SetupSet方法的要点(因此在执行函数之后应该坚持检查定时器对象的属性,这似乎在将SetupSet方法放入代码之前有效)?如果是这样,你能否解释一下SetupSet的存在。谢谢。

2 个答案:

答案 0 :(得分:4)

由于您使用new Mock<IDispatcherTimer>()创建模拟,因此默认为Loose模拟行为。这意味着当模拟对象以未通过Setup方法指定的方式使用时,它不会抱怨。使用接受MockBehavior枚举并指定Strict的构造函数重载将使代码行为与您期望的一样。看起来这就是你期望用Setup次电话判断它的方式;如果你使用松散的嘲笑,它们将是不必要的。

或者,您可以保留松散的模拟,并在预期设置后将SetupSet的{​​{1}}更改为Interval。即:

VerifySet

这就像一个测试断言,意味着如果在调用它时一组var ageService = new AgeUpdatingService(timer); TimeSpan interval = TimeSpan.FromMinutes(10); TimeSpan tolerance = TimeSpan.FromMilliseconds(100) ageService.AddParticipant(new Participant{ DOB = DateTime.Now + interval }); mockTimer.VerifySet(m => m.Interval = It.IsInRange( interval - tolerance, interval + tolerance, Range.Inclusive)); 属性从未发生过,它将抛出一个Interval并且无法通过测试。

答案 1 :(得分:1)

SetupSet可用于设置属性设置器 - 需要这样做是相当不寻常的,因为传递给Set的参数通常不需要捕获,因为可以使用以下方法验证对Setter的调用在“行动”步骤之后VerifySet

这是实现目标的方法:

     var mockTimer = new Mock<ITimer>();

     // Simulate the actions of the Sut with the Mock
     mockTimer.Object.Interval = 6;
     mockTimer.Object.Interval = 7;
     mockTimer.Object.Interval = 999;

     // Ensure the mock was called in-band
     mockTimer.VerifySet(m => m.Interval = It.IsInRange(5, 10, Range.Inclusive), 
            Times.Exactly(2));
     // Ensure the mock was not called out of band
     mockTimer.VerifySet(m => m.Interval = It.Is<int>(i => i < 5 || i > 10),
           Times.Never);

另一种不太优雅的方法是使用SetupSet直接检测无效的调用:

     mockTimer.SetupSet(m => m.Interval = It.Is<int>(i => i < 5 || i > 10))
        .Throws(new ArgumentOutOfRangeException());