Friday, May 15, 2015

Using MOQ to Test Whether a Method Was Called

I use MOQ for my server-side unit testing.  It's pretty easy to get started with and it's always done everything I needed it to do... until recently.

I needed to test whether a method was called with a specific set of parameters.  The result wasn't really important (because the method being called was mocked to do nothing anyway) and the method didn't have a return type so there was no way to validate the results of the method call.  I really just needed to know whether the method was called at all.  It turns out MOQ can do that, too.

The method that needs to be tested:
   1:  public void MethodUnderTest(CustomComplexObject customComplexObject)
   2:  {
   3:      var someLocalVariable = false;
   4:      
   5:      MethodThatShouldBeCalled(customComplexObject.Id, customComplexObject.UserId, someLocalVariable);
   6:      
   7:      /*snip*/
   8:  }

The method that should be called by the method that needs to be tested (this method must be virtual):
   1:  public virtual void MethodThatShouldBeCalled(int id, int userId, bool shouldDoSomethingSpecial)
   2:  {
   3:      if (shouldDoSomethingSpecial)
   4:      {
   5:          /*snip*/
   6:      }
   7:      else
   8:      {
   9:          /*snip*/
  10:      }
  11:  }

The test (an important note is the usage of "CallBase = true"; this won't work unless you include that):
   1:  [TestMethod]
   2:  public void MethodUnderTestShouldCallMethodThatShouldBeCalled()
   3:  {
   4:      // arrange
   5:      // create a new mocked BusinessManager
   6:      // note that this is mocking a concrete object and not an interface
   7:      var moqBusinessManager = new Mock<BusinessManager>{CallBase = true};
   8:      
   9:      // create a test object to pass to MethodUnderTest
  10:      var customComplexObject = new CustomComplexObject
  11:      {
  12:          Id = 123456789,
  13:          UserId = 987654321
  14:      };
  15:      
  16:      // setup the mocked BusinessManager so that MOQ knows what it should keep track of
  17:      moqBusinessManager.Setup(p => p.MethodThatShouldBeCalled(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<bool>()))
  18:          .Verifiable("MethodThatShouldBeCalled was not called");
  19:      
  20:      // act
  21:      // execute MethodUnderTest with the test object
  22:      // note the user of .Object
  23:      moqBusinessManager.Object.MethodUnderTest(customComplexObject);
  24:      
  25:      // assert
  26:      // use MOQ to verify that MethodThatShouldBeCalled was called with the expected parameters
  27:      moqBusinessManager.Verify(p => p.MethodThatShouldBeCalled(123456789, 987654321, false));
  28:  }

No comments:

Post a Comment