【问题标题】:Mock callback in order edge case bug订单边缘情况下的模拟回调错误
【发布时间】:2013-06-17 21:14:06
【问题描述】:

我创建了一个扩展方法,用于按照this SO answer 按顺序调用 moq(见下文)。

一个示例用例是:

mock.setup.CallbackSequence(new List{h,e,l,l,o})

我将hello 传递到我的SUT 并期望字符按顺序排列。

问题是这种情况:

mock.setup.CallbackSequence(new List{h,e,l,l,o,X})

我在哪里经过hello。即使由于动态断言性质(X 从未发送过,但我们永远不知道)它应该失败,这也会通过。我能想到解决这个问题的唯一方法是添加一个

mock.Verify(setupmethod, Times.Exactly(list.Count))

但是,回调设置和验证是在两个不同的地方完成的,所以它会落在扩展方法的使用者身上来实现这个缺陷。我想避免把它放在他们身上,因为它肯定会失败......建议?

public static ICallbackResult CallbackSequence<TMockType, T1, T2>(this ISetup<TMockType> mockSetup, IList<T1> sequencedList) where TMockType : class
{
  //Refactor: Does not fail if it does not reach the end, only if out of order and/or too long
  var index = 0;
  return mockSetup.Callback((T1 t1, T2 t2) =>
  {
    if(index >= sequencedList.Count)
      Assert.That(false, "Sequenced list attempted to access index out of bounds. Count is " + sequencedList.Count + "; index is " + index + "; value being checked is " + t1);
    var currentItemInSequence = sequencedList[index];
    Assert.That(t1, Is.EqualTo(currentItemInSequence), String.Format("Failed sequence at position{0}", index));
    index++;
  });
}

编辑

我能想到的唯一可行的方法是返回一个消费者应该在最后调用的自定义对象:

var sequenceVerifier = ...CallbackSequence();
//Do Stuff
sequenceVerifier.VerifySequence();

这对我来说仍然不是最佳的,因为这给人的印象是在调用 VerifySequence 之前它不会验证,但它只会执行边缘情况......除非我不在回调中断言,而只是最后跟踪并断言??????这可能行得通,想法????

【问题讨论】:

    标签: c# unit-testing mocking moq


    【解决方案1】:

    在与一些同事交谈后,我们提出了一种双重方法,将其留给实施者。

    选项 1

    返回一个必须调用其 VerifySequenceCalls 方法的 SequenceVerifier

    选项 2

    将我的操作传递给辅助方法,以便它可以设置、操作并验证边缘情况

    我可以在第二个选项中使用 SequenceVerifier。然后,由消费者决定他们希望他们的代码看起来如何。

    public static MockSequenceVerifier<T1> CallbackInOrderOfSequence<TMockType, T1, T2>(this ISetup<TMockType> mockSetup, IList<T1> sequencedList) where TMockType : class
    {
      var mockSequenceVerifier = new MockSequenceVerifier<T1>(sequencedList);
      mockSetup.Callback((T1 t1, T2 t2) => mockSequenceVerifier.UpdateSequence(t1));
      return mockSequenceVerifier;
    }
    
    public static void VerifySequenceAfterActionPerformed<TMockType, T1, T2>(this ISetup<TMockType> mockSetup, IList<T1> sequencedList, Action actionToPerform) where TMockType : class
    {
      var verifier = CallbackInOrderOfSequence<TMockType, T1, T2>(mockSetup, sequencedList);
      actionToPerform();
      verifier.VerifySequence();
    }
    
    public class MockSequenceVerifier<T>
    {
      private IList<T> SequenceToVerifyAgainst { get; set; } 
      private IList<T> ActualSequence { get; set; } 
    
      public MockSequenceVerifier(IList<T> sequenceToVerifyAgainst)
      {
        SequenceToVerifyAgainst = sequenceToVerifyAgainst;
        ActualSequence = new List<T>();
      } 
    
      public void VerifySequence()
      {
        ActualSequence.IsEqualTo(SequenceToVerifyAgainst);
      }
    
      public void UpdateSequence(T item)
      {
        ActualSequence.Add(item);
      }
    }
    

    【讨论】:

    • 还没有验证这个答案的正确性,但我相信自学者是好的。
    • @KenKin 我在验证正确后添加了代码
    猜你喜欢
    • 2012-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-04
    • 1970-01-01
    相关资源
    最近更新 更多