Thoughts from the Wet Coast

The musings of an ASP.NET Developer from Canada's We(s)t Coast

DNN Development Tips:9 - Using Moq, the “It” class

Tags: testing moq It
Last Modified: May 2 2017
Oct 22 2014

In a previous article in this series of blog posts, I introduced Moq (Mock-you) – the mocking framework we are using in DNN to generate Mock objects for testing.

In this article I will start to dive deeper into this framework by looking at the unusually named “It” class.

What is “It”?

“It” is a static helper class that provides 4 static methods that allows testers to match a method invocation with an arbitrary value, with a value in a specified range, or even one that matches a given predicate.

The four methods it provides are:

  1. Is(Expression>)
  2. IsAny
  3. IsInRange(TValue from, TValue to, Range rangeKind)
  4. IsRegex(string regex) (+ overloads)

    The name of the class, while it appears strange, allows us to write readable tests.

    For example, continuing our use of the VocabularyController class, lets look at a test for the AddVocabulary method.  Listing 1 shows the AddVocabulary method.

    Listing 1: The AddVocabulary method of VocabularyController

       1:  public int AddVocabulary(Vocabulary vocabulary)
       2:  {
       3:      //Argument Contract
       4:      Requires.NotNull("vocabulary", vocabulary);
       5:      Requires.PropertyNotNullOrEmpty("vocabulary", "Name", vocabulary.Name);
       6:      Requires.PropertyNotNegative("vocabulary", "ScopeTypeId", vocabulary.ScopeTypeId);
       7:   
       8:      vocabulary.VocabularyId = _DataService.AddVocabulary(vocabulary, UserController.Instance.GetCurrentUserInfo().UserID);
       9:   
      10:      //Refresh Cache
      11:      DataCache.RemoveCache(_CacheKey);
      12:   
      13:      return vocabulary.VocabularyId;
      14:  }

    As in the previous article, one of the tests we need to write is a test that confirms that the VocabularyId property of the vocabulary is set to the value returned from the call to the DataService (line 8).

    Listing 2: Testing that the VocabularyController’s AddVocabulary method sets the VocabularyId correctly.

       1:  [Test]
       2:  public void VocabularyController_AddVocabulary_Sets_ValidId_On_Valid_Vocabulary()
       3:  {
       4:      //Arrange
       5:      Mock mockDataService = new Mock();
       6:      mockDataService.Setup(ds => ds.AddVocabulary(It.IsAny(), It.IsAny<int>()))
       7:                    .Returns(Constants.VOCABULARY_AddVocabularyId);
       8:   
       9:      VocabularyController vocabularyController = new VocabularyController(mockDataService.Object);
      10:   
      11:      Vocabulary vocabulary = ContentTestHelper.CreateValidVocabulary();
      12:   
      13:      //Act
      14:      vocabularyController.AddVocabulary(vocabulary);
      15:   
      16:      //Assert
      17:      Assert.AreEqual<int>(Constants.VOCABULARY_AddVocabularyId, vocabulary.VocabularyId);
      18:  }

    In this example we make use of the “It” class in the Setup method of the Mock.  This code is pretty self-explanatory.  In the set up, as long as the mock DataService’s AddVocabulary method is given any Vocabulary instance (It.IsAny()) and any integer (It.IsAny()) it should return a known VocabularyId (Constants.VOCABULARY.AddVocabularyId).

    The beauty of this class is it is clear what the methods are being used for.

    It.IsAny() – means accept any instance of IFoo

    It.Is(i => i%2 == 0) – means accept any even number (or any integer which is divisible by 2)

    For example:

    // given any value return true mock.Setup(foo => foo.Execute(It.IsAny<string>())).Returns(true);   // given any even number return true mock.Setup(foo => foo.Add(It.Is<int>(i => i % 2 == 0))).Returns(true);    // If the value is between 1 and 10 return true mock.Setup(foo => foo.Add(It.IsInRange<int>(0, 10, Range.Inclusive))).Returns(true);    // If the string matches the Regex [a-d]+, return "foo" mock.Setup(x => x.Execute(It.IsRegex("[a-d]+", RegexOptions.IgnoreCase))).Returns("foo");
     

    We can also use it in the Assert phase to verify that a method was called with a particular value..

    // assert Execute was called - with any string mock.Verify(foo => foo.Execute(It.IsAny<string>()));   // assert Add was called with an even number mock.Verify(foo => foo.Add(It.Is<int>(i => i % 2 == 0)));    // assert Add was called with a value between 1 and 10 return mock.Verify(foo => foo.Add(It.IsInRange<int>(0, 10, Range.Inclusive))); 

    The “It” class provides readable matching conditions and is an important part of the Moq framework.  In the next part of this series I will continue to dive deeper into this awesome mocking framework.

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

    Categories

    Tags