Using Moq to verify calls are made in the correct order

后端 未结 8 1707
青春惊慌失措
青春惊慌失措 2020-12-01 10:00

I need to test the following method:

CreateOutput(IWriter writer)
{
    writer.Write(type);
    writer.Write(id);
    writer.Write(sender);

    // many more         


        
8条回答
  •  孤街浪徒
    2020-12-01 10:58

    I wrote an extension method that will assert based on order of invocation.

    public static class MockExtensions
    {
      public static void ExpectsInOrder(this Mock mock, params Expression>[] expressions) where T : class
      {
        // All closures have the same instance of sharedCallCount
        var sharedCallCount = 0;
        for (var i = 0; i < expressions.Length; i++)
        {
          // Each closure has it's own instance of expectedCallCount
          var expectedCallCount = i;
          mock.Setup(expressions[i]).Callback(
            () =>
              {
                Assert.AreEqual(expectedCallCount, sharedCallCount);
                sharedCallCount++;
              });
        }
      }
    }
    

    It works by taking advantage of the way that closures work with respect to scoped variables. Since there is only one declaration for sharedCallCount, all of the closures will have a reference to the same variable. With expectedCallCount, a new instance is instantiated each iteration of the loop (as opposed to simply using i in the closure). This way, each closure has a copy of i scoped only to itself to compare with the sharedCallCount when the expressions are invoked.

    Here's a small unit test for the extension. Note that this method is called in your setup section, not your assertion section.

    [TestFixture]
    public class MockExtensionsTest
    {
      [TestCase]
      {
        // Setup
        var mock = new Mock();
        mock.ExpectsInOrder(
          x => x.MyMethod("1"),
          x => x.MyMethod("2"));
    
        // Fake the object being called in order
        mock.Object.MyMethod("1");
        mock.Object.MyMethod("2");
      }
    
      [TestCase]
      {
        // Setup
        var mock = new Mock();
        mock.ExpectsInOrder(
          x => x.MyMethod("1"),
          x => x.MyMethod("2"));
    
        // Fake the object being called out of order
        Assert.Throws(() => mock.Object.MyMethod("2"));
      }
    }
    
    public interface IAmAnInterface
    {
      void MyMethod(string param);
    }
    

提交回复
热议问题