Archive

Archive for April, 2013

Mocking Sitecore with Microsoft Fakes part 3

12/04/2013 2 comments

This will be that last in this series Mocking Sitecore with Microsoft Fakes Links to Part 1 and Part 2 . To end end th series I will revisted a old blog post found here. In the original post I I created a TestItem, to test some old Production code. So in this post i will Test the same piece code.

First a view of the code we want to test.


 public class NavigationTitleFactory
 {
    public static string Create(Item item)
    {
      bool showInNavigation = item.GetCheckBoxValue(Constants.Fields.Navigable.ShowInMenu);

      if (!showInNavigation)
      {
         return string.Empty;
      }
      string navigationTitle = item.GetString(Constants.Fields.Navigable.Title);

      if (string.IsNullOrEmpty(navigationTitle))
        navigationTitle = item.Name;

      return navigationTitle;
    }
 }

With code above there a two ways we can test it. We could as in the original post create an Item mock using fakes, or we could overwrite the extension method something that is not possible with ordinary mocking frameworks.

Here below I will create an Item Mock.

[TestMethod]
  public void CreateItemWithShowInMenuFalseShouldReturnEmptyString()
  {

    string expectedNavigationTitle = "NavigationTitel";
    using (ShimsContext.Create())
    {
       Field showInMenu = new ShimField()
      {
        IDGet = () => Constants.Fields.Navigable.ShowInMenu,
        ValueGet = () => "0"
      };

      Field navigationTitle = new ShimField()
     {
       IDGet = () => Constants.Fields.Navigable.Title,
       ValueGet = () => expectedNavigationTitle
      };

     FieldCollection fieldCollection = new ShimFieldCollection()
     {
       ItemGetID = (id) => id == Constants.Fields.Navigable.ShowInMenu ? showInMenu : id ==                          Constants.Fields.Navigable.Title ? navigationTitle : null
     };

     Item itemStub = new ShimItem() { FieldsGet = () => fieldCollection };
     string actualNavigationTitle = NavigationTitleFactory.Create(itemStub);

     Assert.AreSame(string.Empty, actualNavigationTitle);
   }
 }

 [TestMethod]
 public void CreateItemWithShowInMenuTrueNoNavigationTitleShouldReturnItemName()
 {
   using (ShimsContext.Create())
   {
     Field showInMenu = new ShimField()
     {
       IDGet = () => Constants.Fields.Navigable.ShowInMenu,
       ValueGet = () => "1"
     };

     Field navigationTitle = new ShimField()
     {
       IDGet = () => Constants.Fields.Navigable.Title,
       ValueGet = () => string.Empty
      };

     FieldCollection fieldCollection = new ShimFieldCollection()
     {
       ItemGetID = id => id == Constants.Fields.Navigable.ShowInMenu ? showInMenu : id == Constants.Fields.Navigable.Title ? navigationTitle : null
     };

     string expectedItemName = "Name";
     Item itemStub = new ShimItem() { FieldsGet = () => fieldCollection, NameGet = () => expectedItemName };

     string actualNavigationTitle = NavigationTitleFactory.Create(itemStub);

     Assert.AreSame(expectedItemName, actualNavigationTitle);
   }
 }

 [TestMethod]
 public void CreateItemWithShowInMenuTrueShouldReturnItemNavigationTitle()
 {
   using (ShimsContext.Create())
  {
    string expectedNavigationTitle = "Navigation Title";
    Field showInMenu = new ShimField()
    {
      IDGet = () => Constants.Fields.Navigable.ShowInMenu,
      ValueGet = () => "1"
     };

     Field navigationTitle = new ShimField()
     {
       IDGet = () => Constants.Fields.Navigable.Title,
       ValueGet = () => expectedNavigationTitle
     };

    FieldCollection fieldCollection = new ShimFieldCollection()
    {
      ItemGetID = id => id == Constants.Fields.Navigable.ShowInMenu ? showInMenu : id == Constants.Fields.Navigable.Title ? navigationTitle : null
    };

    Item itemStub = new ShimItem
    {
      IDGet = () => ID.NewID,
      FieldsGet = () => fieldCollection,
    };

    string actualNavigationTitle = NavigationTitleFactory.Create(itemStub);

    Assert.AreSame(expectedNavigationTitle, actualNavigationTitle);
  }
}

Since the code only use extension methods to access item data it might make more sense to overwrite these methods to isolate any faulty implementations of item access in the extensions methods. This is shown below.

[TestMethod]
   public void EXTENSION_CreateItemWithShowInMenuFalseShouldReturnEmptyString()
   {
      using (ShimsContext.Create())
      {
        Item itemStub = new ShimItem();
        ShimItemExtensions.GetCheckBoxValueItemID = (item, id) => { return false; };
        string actualNavigationTitle = NavigationTitleFactory.Create(itemStub);

        Assert.AreSame(string.Empty, actualNavigationTitle);
      }
   }

  [TestMethod]
  public void EXTENSION_CreateItemWithShowInMenuTrueNoNavigationTitleShouldReturnItemName()
  {
     using (ShimsContext.Create())
     {
       string expectedItemName = "Name";
       Item itemStub = new ShimItem(){ NameGet = () => expectedItemName};
       ShimItemExtensions.GetCheckBoxValueItemID = (item, id) => true;
       ShimItemExtensions.GetStringItemID = (item, id) => string.Empty;

       string actualNavigationTitle = NavigationTitleFactory.Create(itemStub);

       Assert.AreSame(expectedItemName, actualNavigationTitle);
     }
  }

 [TestMethod]
 public void EXTENSION_CreateItemWithShowInMenuTrueShouldReturnItemNavigationTitle()
 {
    using (ShimsContext.Create())
    {
       string expectedNavigationTitle = "Navigation Title";
       Item itemStub = new ShimItem();

       ShimItemExtensions.GetCheckBoxValueItemID = (item, id) => true;
       ShimItemExtensions.GetStringItemID = (item, id) => expectedNavigationTitle;
       string actualNavigationTitle = NavigationTitleFactory.Create(itemStub);

       Assert.AreSame(expectedNavigationTitle, actualNavigationTitle);
    }
 }

The result of the test

part3a

This was the last part in this series. I hope this covers the most basic mocking of Sitecore, which until vs 2012 update wasn’t possible Otherwise let me know… 🙂

Advertisements
Categories: .Net, C#, Unit Testing Tags: , , ,

Mocking Sitecore with Microsoft Fakes part 2

10/04/2013 6 comments

In this post I will continue where part 1 left, you can find part 1 here. This post will be rich with examples on how to use Microsoft fakes, now included in VS 2012 Premium, to mock out different parts of Sitecore. All the Examples  has been chosen, because I think they include some of the most used functions or interactions with Sitecore. They are all really small example, and you can off course combine them as you like.

 

To start with lets take a look at the Sitecore Item and some of the properties not covered in part 1.

 [TestMethod]
 public void Mocking_ItemProperties()
 {
    using (ShimsContext.Create())
    {
      ID expectedId = ID.NewID;
      ID expectedTemplateId = ID.NewID;
      string expectedName = "ShimItem";
      string expectedDisplayName = "ShimItem";

      //Setting some of the most used properties on a Item
      Item item = new ShimItem()
      {
         IDGet = () => expectedId,
         NameGet = () => expectedName,
         DisplayNameGet = () => expectedDisplayName,
         TemplateIDGet = () => expectedTemplateId
      };

      Assert.AreSame(expectedId, item.ID);
      Assert.AreSame(expectedTemplateId, item.TemplateID);
      Assert.AreSame(expectedName, item.Name);
     Assert.AreSame(expectedDisplayName, item.DisplayName);
   }

 }

 [TestMethod]
 public void Mocking_Item_Children()
 {
    using (ShimsContext.Create())
    {
      //Setup an valid item list you can add more item properties if you like
      List<Item> childList = new List<Item>();
      childList.Add(new ShimItem() { NameGet = () => "1" });
      childList.Add(new ShimItem() { NameGet = () => "2" });
      childList.Add(new ShimItem() { NameGet = () => "3" });
      childList.Add(new ShimItem() { NameGet = () => "4" });
      childList.Add(new ShimItem() { NameGet = () => "5" });

      ChildList children = new ShimChildList()
      {
        GetEnumerator = () => childList.GetEnumerator(),
        CountGet = () => childList.Count
      };

      Item item = new ShimItem()
      {
        ChildrenGet = () => children
      };

      Assert.AreEqual(item.Children.Count,childList.Count);
      foreach (Item child in item.Children)
      {
        Assert.IsFalse(string.IsNullOrEmpty(child.Name));
      }
    }
 }

With that covered lets see some examples of how to mock the Sitecore Database.

[TestMethod]
  public void Mocking_Database_GetName()
  {
     using (ShimsContext.Create())
     {
       string expectedName = "web";
       Database database = new ShimDatabase()
        {
NameGet = () => expectedName
        };
        Assert.AreEqual(expectedName, database.Name);
    }
}

   [TestMethod]
   public void Mocking_Database_GetRootITem()
   {
     using (ShimsContext.Create())
     {
       string expectedItemName = "Shim";
       Item item = new ShimItem()
         {
          NameGet = () => expectedItemName
         };
       Database database = new ShimDatabase()
       {
         GetRootItem = () => item
       };

       Item rootItem = database.GetRootItem();

      Assert.AreEqual(expectedItemName, rootItem.Name);
    }
  }

Finally lets combine the two above and try to mock the Static context of Sitecore. How often have you wrote Sitecore.Context.Item, Sitecore.Context.Site or Sitecore.Context.Database.


 [TestMethod]
 public void Mocking_Context_Item()
 {
    using (ShimsContext.Create())
    {
      string expectedName = "CurrentItem";
      Item item = new ShimItem()
       {
          NameGet =()=> expectedName
       };

     ShimContext.ItemGet = () => item;

     Item contextItem = Sitecore.Context.Item;

     Assert.AreEqual(expectedName, contextItem.Name);
   }
 }

 [TestMethod]
 public void Mocking_Context_Database()
 {
   using (ShimsContext.Create())
   {
     string expectedDatabaseName = "web";
     Database database = new ShimDatabase()
       {
        NameGet = () => expectedDatabaseName
       };

    ShimContext.DatabaseGet = () => database;

    Database currentDatabase = Sitecore.Context.Database;

    Assert.AreEqual(expectedDatabaseName, currentDatabase.Name);
  }
 }

 [TestMethod]
 public void Mocking_Context_Site()
 {
   using (ShimsContext.Create())
   {
     string expectedName = "CurrentItem";
     Item item = new ShimItem()
     {
       NameGet =()=> expectedName,
     };

    string expectedDatabaseName = "web";
    Database database = new ShimDatabase()
     {
      NameGet = () => expectedDatabaseName
     };

    SiteContext siteContext = new ShimSiteContext()
     {
       StartItemGet = () => item.Name,
       DatabaseGet = () => database
     };

    ShimContext.SiteGet = () => siteContext;
    SiteContext context = Sitecore.Context.Site;

    Assert.AreEqual(expectedDatabaseName, context.Database.Name);
    Assert.AreEqual(expectedName, context.StartItem);
  }

}

With that i think we pretty much covered some of the most used properties and method from Sitecore, without creating wrappers. If there are some missed examples of examples you would like to see please say so.

Otherwise stay tuned for Part 3.

Mocking Sitecore with Microsoft Fakes part 1

08/04/2013 12 comments

This post have been  in making for a while or since the Visual Studio 2012 Update 2 was announced. Especially since the update added Microsoft Fakes to VS 2012 Premium. With Fakes it is now possible to mock  Static methods and otherwise unmockable class’ for example DataTime.Now or a Sitecore Item. So now finally it is possible to do unit testing with Sitecore or if you like TDD. I know that this has been possible for a while if you used Glass Mapper og had access to a Typemock license.

This post is the first in a small series, on how to mock Sitecore out using Microsoft Fakes, and to begin with, I will have a look and extracting data from a Sitecore Item.

The two ways to get data from item i will cover here is either accessing a field through the field collection using item.Field[name of your field] or by the indexing found on the BaseItem which Item derives from like this item[name of your field].

The two code snippets below is used to run my test against one uses Field[] the other Item[]

 

public class CodeSnippet
{
   public static ID MY_TEXT_FIELD = new ID("{dc321650-5b1d-479a-ae81-c04d6585140d}");
   public static ID MY_CHECKBOX_FIELD = new ID("{a007c875-5192-4068-864d-523ffaa0b4ca}");
   public static string MISSING_TEXT = "MISSING TEXT";

   public string RunWithDataFromFieldCollection(Item item)
   {

      CheckboxField checkboxField = new CheckboxField(item.Fields[MY_CHECKBOX_FIELD]);
      if (checkboxField.Checked)
      {
        TextField textField = new TextField(item.Fields[MY_TEXT_FIELD]);
        string textValue = textField.Value;
        if (!string.IsNullOrEmpty(textValue))
          return textValue;
        return MISSING_TEXT;
      }
      return string.Empty;
  }

  public string RunWithDataFromBaseCustomItemIndex(Item item)
  {
    bool isChecked = item[MY_CHECKBOX_FIELD] == "1";
    if (isChecked)
    {
      string textValue = item[MY_TEXT_FIELD];
      if (!string.IsNullOrEmpty(textValue))
       return textValue;
      return MISSING_TEXT;
    }
    return string.Empty;
  }
}

First we look at the code that uses the Field[], This example is much like using the TestItem if used in earlier post found here, or at least the setup is. You need to setup a fieldcollection and ensure that the fields used exists in the collection.

 [TestClass]
 public class TestFieldAccess
 {
    private CodeSnippet _codeSnippet;

   [TestInitialize]
   public void Initialize()
   {
     _codeSnippet = new CodeSnippet();
   }

   [TestCleanup]
   public void CleanUp()
   {
     _codeSnippet = null;
   }

   [TestMethod]
   public void Run_WithCheckboxFieldNotChecked_ShouldReturnEmptyString()
   {
     using (ShimsContext.Create())
     {
       Field checkBoxField = new ShimField()
       {
         IDGet = () => CodeSnippet.MY_CHECKBOX_FIELD,
         ValueGet = () => "0"
       };
       FieldCollection fieldCollection = new ShimFieldCollection()
       {
         ItemGetID = id => checkBoxField
       };

       Item itemStub = new ShimItem() { FieldsGet = () => fieldCollection};
       string actualText = _codeSnippet.RunWithDataFromFieldCollection(itemStub);

       Assert.AreSame(string.Empty, actualText);
    }
  }

  [TestMethod]
  public void Run_WithCheckboxFieldCheckedButNotTextInTextField_ShouldReturnMissingText()
  {

   using (ShimsContext.Create())
   {
     Field checkBoxField = new ShimField()
     {
       IDGet = () => CodeSnippet.MY_CHECKBOX_FIELD,
       ValueGet = () => "1"
     };
     Field textField = new ShimField()
     {
      IDGet = () => CodeSnippet.MY_TEXT_FIELD,
      ValueGet = () =>string.Empty
     };
     FieldCollection fieldCollection = new ShimFieldCollection()
     {
      ItemGetID = id => id==CodeSnippet.MY_CHECKBOX_FIELD ?checkBoxField : id == CodeSnippet.MY_TEXT_FIELD ? textField : null
     };

     Item itemStub = new ShimItem() { FieldsGet = () => fieldCollection };
     string actualText = _codeSnippet.RunWithDataFromFieldCollection(itemStub);

     Assert.AreSame(CodeSnippet.MISSING_TEXT, actualText);
    }
   }

  [TestMethod]
  public void Run_WithCheckboxFieldCheckedButNotTextInTextField_ShouldReturnActualTextFromTextField()
  {
    using (ShimsContext.Create())
    {
     string expectedText = " Should return this string";
     Field checkBoxField = new ShimField()
     {
       IDGet = () => CodeSnippet.MY_CHECKBOX_FIELD,
       ValueGet = () => "1"
     };
     Field textField = new ShimField()
     {
       IDGet = () => CodeSnippet.MY_TEXT_FIELD,
       ValueGet = () => expectedText
     };
    FieldCollection fieldCollection = new ShimFieldCollection()
    {
      ItemGetID = id => id == CodeSnippet.MY_CHECKBOX_FIELD ? checkBoxField : id == CodeSnippet.MY_TEXT_FIELD ? textField : null
    };

    Item itemStub = new ShimItem() { FieldsGet = () => fieldCollection };

     string actualText = _codeSnippet.RunWithDataFromFieldCollection(itemStub);

     Assert.AreSame(expectedText, actualText);
    }
   }
 }

and the result off course 3 green bars with 100 % test coverage.

 mocksitecorepart1a

And yes there is a lot of setup.

Now lets look at the indexing, here it becomes a little tricky since the derived BaseItem public methods isn’t overwritten on a ShimItem there for we will have to fake calls to BaseItem instead of the Item but still we need to create a stub of the item with ShimItem.

 

 [TestClass]
 public class TestIndexAccess
 {
   private CodeSnippet _codeSnippet;

   [TestInitialize]
   public void Initialize()
   {
     _codeSnippet = new CodeSnippet();
   }

   [TestCleanup]
   public void CleanUp()
   {
    _codeSnippet = null;
   }

   [TestMethod]
   public void Run_WithCheckboxFieldNotChecked_ShouldReturnEmptyString()
   {
     using (ShimsContext.Create())
     {
      ShimBaseItem.AllInstances.ItemGetID = (item, id) => "0";
      Item itemStub = new ShimItem();
      string actualText = _codeSnippet.RunWithDataFromBaseCustomItemIndex(itemStub);
      Assert.AreSame(string.Empty, actualText);
     }
   }

  [TestMethod]
  public void Run_WithCheckboxFieldCheckedButNotTextInTextField_ShouldReturnMissingText()
  {
     using (ShimsContext.Create())
     {
      ShimBaseItem.AllInstances.ItemGetID = (item, id) => id == CodeSnippet.MY_CHECKBOX_FIELD ? "1" : id == CodeSnippet.MY_TEXT_FIELD ? string.Empty : null;
      Item itemStub = new ShimItem();

      string actualText = _codeSnippet.RunWithDataFromBaseCustomItemIndex(itemStub);

      Assert.AreSame(CodeSnippet.MISSING_TEXT, actualText);
    }
  }

  [TestMethod]
  public void Run_WithCheckboxFieldCheckedButNotTextInTextField_ShouldReturnActualTextFromTextField()
  {
    using (ShimsContext.Create())
    {
       string expectedText = " Should return this string";
       ShimBaseItem.AllInstances.ItemGetID =
        (item, id) => id == CodeSnippet.MY_CHECKBOX_FIELD ? "1" : id == CodeSnippet.MY_TEXT_FIELD ? expectedText : null;

      Item itemStub = new ShimItem();

      string actualText = _codeSnippet.RunWithDataFromBaseCustomItemIndex(itemStub);

      Assert.AreSame(expectedText, actualText);
   }
 }

}
<pre>

 

And once again the result off course 3 green bars with 100 % test coverage.

mocksitecorepart1b

It might no be as smooth as Typemock mocking framework, and yes demands a bit more setup, at least at to begin with.