Archive

Archive for the ‘Sitecore 6’ Category

Using SecurityDisabler and EditContext With Sitecore Fakes

06/11/2013 2 comments

Recently I had to write some code that import a lot of content  for a customer, who on a daily basis wanted to imported  100+ news Items  into Sitecore. Importing and filling out the data field of items isn’t that complex task, or code to write. But I really wanted to test the functionality so I could guarantee and verify the behavior of my code before I released into a running LIVE environment. So I’ve sat myself the goal to extend Sitecore Fakes so I could test against and “Database” in memory instead of cleaning the Sitecore solution every time I’ve ran a test import.

An Example of a simple import code could look something like this

using (new SecurityDisabler())
{
subNode = homeItem.Add("SubNode", templateId);
using (new EditContext(subNode))
{
subNode[fieldIdA] = "test";
subNode[fieldIdB] = "testBBB";
}
}

To do this I’ve had to include some more section in the App.config for the test project. The section is listed below are the changes I’ve added

<authentication defaultProvider="forms">
 <providers>
 <clear />
 <add name="forms" type="Sitecore.Security.Authentication.FormsAuthenticationProvider, Sitecore.Kernel" />
 </providers>
 </authentication>
 <authorization defaultProvider="sql">
 <providers>
 <clear/>
 <add name="sql" type="Sitecore.Fakes.ConfigurationFakes.FakeAutheorizationProvider, Sitecore.Fakes" />
 </providers>
 </authorization>
 <domainManager defaultProvider="file">
 <providers>
 <clear />
 <add name="file" type="Sitecore.Fakes.ConfigurationFakes.FakeDomainProvider, Sitecore.Fakes" />
 </providers>
 </domainManager>
 <accessRights defaultProvider="config">
 <providers>
 <clear />
 <add name="config" type="Sitecore.Fakes.ConfigurationFakes.FakeAccessRight,Sitecore.Fakes" />
 </providers>
 </accessRights>

As you can see the Sitecore Fakes comes with som substitutes from the original configuration section, this implements dummy functionality and helps keeping the app.config file to a minimum. These includes

Sitecore.Fakes.Config.FakeAutheorizationProvider

Sitecore.Fakes.Config.FakeDomainProvider

Sitecore.Fakes.Config.FakeAccessRight

Also the itemprovider have been extended so it now overrides the base functionality for Item.Add(..)

public override Item AddFromTemplate(string itemName, ID templateId, Item destination, ID newId)
 {
 FakeDatabase fakeDatabase = Factory.GetDatabase(destination.Database.Name) as FakeDatabase;
 FakeItem child = new FakeItem(newId, templateId, itemName, fakeDatabase.Name);
 FakeItem fakeParent = destination as FakeItem;
 fakeParent.AddChild(child);
 fakeDatabase.FakeAddItem(child);
 return child;
 }

With these change in place we can now run our test from the beginning.

public void CreateAndEditItemTest()
 {
 //setup database so we have a rood node to add our content to
 var homeFakeItem = new FakeItem();
 Item homeItem = (Item) homeFakeItem;

 //Define some Field IDs
 TemplateID templateId = new TemplateID(ID.NewID);
 Item subNode;
 ID fieldIdA = ID.NewID;
 ID fieldIdB = ID.NewID;

//add and edit the ite,
 using (new SecurityDisabler())
 {
 subNode = homeItem.Add("SubNode", templateId);
 using (new EditContext(subNode))
 {
 subNode[fieldIdA] = "test";
 subNode[fieldIdB] = "testBBB";
 }

}
 subNode[fieldIdA].ShouldAllBeEquivalentTo("test");
 subNode[fieldIdB].ShouldAllBeEquivalentTo("testBBB"); ;
 }

If you need more then one database or another then “web” which is default for Sitecore Fakes either alter or add one more to the DataBase section of your test project so it look like something like below.

<databases>
<database id="web" singleInstance="true" type="Sitecore.Fakes.FakeDatabase, Sitecore.Fakes">
<param desc="name">$(id)</param>
</database>
<database id="master" singleInstance="true" type="Sitecore.Fakes.FakeDatabase, Sitecore.Fakes">
<param desc="name">$(id)</param>
</database>
 </databases>

You Can download Sitecore fakes from github here: https://github.com/istern/Sitecore-Fakes

Getting started with Sitecore Fakes

23/10/2013 Leave a comment

in this post I will give a simple guide that can get you started on using Sitecore Fakes. So you can start doing unit testing with Sitecore.  You can use Sitecore fakes with any testing framework for example Nunit Xunit o any like those.

1. First  you should go and download the the code from github :

https://github.com/istern/Sitecore-Fakes

2.  Once you have downloaded the code start it up in Visual Studio, and fix the missing reference for the Sitecore.Kernel.dll see image below, and then build the project. If the test project fails you can, if you like, fix the missing references for Sitecore.Kernel and Sitecore.Nexus all other references can be updated through nuget. But it is not required to get Sitecore.Fakes to work.

geetingstartedsf

3. Now open the solution that holds the code you want to test and add a new “class library” to the solution. To the newly created project  you will need to add an app.config file and a references off course to the Sitecore .Fakes.dll you just build in step 2. The App.config filles is ONLY REQUIRED if you need to access anything else but the the “Item.Fields” for example the database child colletion and so on. The content for the app.config you can copy in from test project that Sitecore Fakes comes with and has on Github, but as a service i will give it here.

</pre>
<?xml version="1.0"?>
<configuration>
 <configSections>
 <section name="sitecore" type="Sitecore.Configuration.ConfigReader, Sitecore.Kernel"/>
 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, Sitecore.Logging"/>
 </configSections>
 <sitecore database="SqlServer">
 <itemManager defaultProvider="default">
 <providers>
 <clear/>
 <add name="default" type="Sitecore.Fakes.FakeItemProvider,Sitecore.Fakes"/>
 </providers>
 </itemManager>
 <databases>
 <database id="web" singleInstance="true" type="Sitecore.Fakes.FakeDatabase, Sitecore.Fakes">
 <param desc="name">$(id)</param>
 </database>
 </databases>
 <mediaLibrary>
 <mediaProvider type="Sitecore.Fakes.FakeMediaProvider, Sitecore.Fakes"/>
 </mediaLibrary>
 <settings>
 <setting name="LicenseFile" value="C:\license.xml"/>
 </settings>
 </sitecore>
 <log4net>
 </log4net>
</configuration>
<pre>

4. Next add a reference to Sitecore kernel and Sitecore Nexus in the newly created class.
6.  Write your first test and see is Fail …. or Pass

In the future hopefully Sitecore Fakes will be available through nuget so you can skip a few of the steps above. more details aboudt Sitecore Fakes ca be found in my earlier posts here and here

Null ids are not allowed. Parameter name:pipelineID

06/09/2013 Leave a comment

I’ve seen the error shown below a couple of times now and wanted to give a quick fix for it.

 

nullids

 

The error can be difficult to understand. Often this is because of the .net framework for the app-pool is set to .net 4 where the code/site is built against .net 3.5 which is  the same as .net 2.xxx in the app-pool settings.

Categories: Sitecore 6 Tags:

Sitecore Fakes Media Items LinkFields and a challange.

13/06/2013 Leave a comment

When I  first started building the Sitecore Fakes Isolation framework I was given a challenge by Per Bering. The challenge was  to make the following unit test pass.


MediaManager.GetMediaUrl((MediaItem)((LinkField)contenItem.Fields["Thumbnail"]).TargetItem).ShouldAllBeEquivalentTo("/~/media/hello.png");

Passing this test would require for implementation of some more fake objects in existing Sitecore Fakes Framework,  a implementation for easily adding LinkField XML to an field “General Link Field in this case” ,  make the mapping to the TargetItem And create it. Creating a fake media Item, and replacing the default Media Provider used by the MediaManager.

The Fake Intenal Link Field, builds the XML required for casting in to the real LinkField, so it derives from a FakeField which build the XML allmost like Sitecore Does it.

Here is the FakeField and FakeLinkField no getters is placed on the FakeLinkField since I expected values to be fetch through the regular LinkField.

FAKEFIELD:

public class FakeField
 {
 public FakeField(string xmlString)
 {
 XMLDocument = XmlUtil.LoadXml(xmlString);
 }

 public void SetAttribute(string name, string value)
 {
 XmlUtil.SetAttribute(name, "", value, XMLDocument.FirstChild);
 }

public XmlDocument XMLDocument;
 }

FAKELINKFIELD

public class FakeInternalLinkField : FakeLinkField
 {
 public FakeInternalLinkField(Item itemToLinkTo,string target="",string url = "", string text="", string anchor="",string querystring="" ,string title="" ,string cssclass="")
 {
 SetLinkToItem(itemToLinkTo);
 Target = target;
 Url = url;
 Text = text;
 Anchor = anchor;
 QueryString = querystring;
 Title = title;
 Class = cssclass;
 LinkType = "internal";
 }

private void SetLinkToItem(Item itemToLinkTo)
 {
 ((FakeDatabase) Factory.GetDatabase(itemToLinkTo.Database.Name)).FakeAddItem(itemToLinkTo);
 TargetItem = itemToLinkTo;
 }

public override string ToString()
 {
 return XMLDocument.InnerXml;
 }
 }

When adding the  FakeLinkField to an field on a FakeItem simply call the .ToString() and build the XML for a regular LinkField from Sitecore. See Example below.

[Fact]
 public void Field_AddingLinkFieldWithLinkFromOneItemToAnother_TargetItemShouldReturnLinkedToItem()
 {
 Item linkedToItem = new FakeItem();
 FakeInternalLinkField fakeLinkField = new FakeInternalLinkField(linkedToItem);

 ID fieldId = ID.NewID;
 FieldList fieldCollection = new FieldList();
 fieldCollection.Add(fieldId,fakeLinkField.ToString());

Item itemToLinkFrom = new FakeItem(fieldCollection);

LinkField sitecoreLinkField = (LinkField) itemToLinkFrom.Fields[fieldId];

 sitecoreLinkField.TargetItem.ID.ShouldBeEquivalentTo(linkedToItem.ID);
 }

With that in place the inner part of challenges is now passing.

Next was the TypeCast to a MedaiItem, again creating a FAkeMedia Item ad mapping all the field passed in all most does the job. BUT sitecore asks for field values using their names so an additional mapping from id to field named is required, Sitecore Fakes now mappes most of the standard field on an imageItem from Sitecore using the MediaField setting file se both below.

public class FakeMediaItem : MediaItem
 {
 private readonly MediaStandardFields _mediaStandardFields;
 public FakeMediaItem(string name = "" ,string filepath="", string alt="", string width="",string height="",string title="",string keywords="",string extension="",string mimetype="",string size="" ) :
 base(CreateDataItem(name,filepath,alt,width,height,title,keywords,extension,mimetype,size))
 {
 _mediaStandardFields = new MediaStandardFields();
 }

private static Item CreateDataItem(string name,string filepath, string alt, string width, string height, string title, string keywords, string extension, string mimetype, string size)
 {
 FieldList fieldList = CreateFieldList(filepath, alt, width, height, title, keywords, extension, mimetype, size);
 FakeItem dataItem = new FakeItem(fieldList,name);

 AddMediaItemFieldMappings(dataItem);

 return dataItem;
 }

private static FieldList CreateFieldList(string filepath, string alt, string width, string height, string title,
 string keywords, string extension, string mimetype, string size)
 {
 FieldList fieldList = new FieldList();

fieldList.Add(MediaStandardFields.FilePathId, filepath);
 fieldList.Add(MediaStandardFields.AltId, alt);
 fieldList.Add(MediaStandardFields.WidthId, width);
 fieldList.Add(MediaStandardFields.HeightId, height);
 fieldList.Add(MediaStandardFields.TitleId, title);
 fieldList.Add(MediaStandardFields.KeywordsId, keywords);
 fieldList.Add(MediaStandardFields.ExtensionId, extension);
 fieldList.Add(MediaStandardFields.MimetypeId, mimetype);
 fieldList.Add(MediaStandardFields.SizeId, size);
 return fieldList;
 }



And the FieldMappings

 public class MediaStandardFields
 {
 public static ID FilePathId = ID.NewID;
 public static ID AltId = ID.NewID;
 public static ID WidthId = ID.NewID;
 public static ID HeightId = ID.NewID;
 public static ID TitleId = ID.NewID;
 public static ID KeywordsId = ID.NewID;
 public static ID ExtensionId = ID.NewID;
 public static ID MimetypeId = ID.NewID;
 public static ID SizeId = ID.NewID;
 public static string FilePath = "file path";
 public static string Alt = "Alt";
 public static string Width = "Width";
 public static string Height = "Height";
 public static string Title = "Title";
 public static string Keywords = "Keywords";
 public static string Extension = "Extension";
 public static string Mimetype = "Mime type";
 public static string Size = "size";

public MediaStandardFields()
 {
 }
 }

Now missing is the replacement for the fake media provide switching is fairly easy but changing in the app.config file


<mediaLibrary>
 <mediaProvider type="Sitecore.Fakes.FakeMediaProvider, Sitecore.Fakes" />
 </mediaLibrary>

Since this is a first release and to make the test pass with out writting to much code I’m gonna give the premise that and media url is build from the item name and the type extesion , prefixed with “/~/media library/”. Here is is rather simple implementation of the Fake Media Provider.

 public class FakeMediaProvider : MediaProvider
 {
 public override string GetMediaUrl(MediaItem item)
 {
 Item sourceItem = item;
 return String.Format("/~/media/{0}.{1}", sourceItem.Name, sourceItem[MediaStandardFields.ExtensionId]);
 }
 }

And Now Lets See the “unit test” / challenge pass.

[Test]
 public void The_Per_Bering_Challnange()
 {
 MediaItem mediaItem = new FakeMediaItem("hello",extension:"png");

ID linkFieldId = ID.NewID;
 FakeInternalLinkField fakeLinkField = new FakeInternalLinkField(mediaItem);

FieldList fieldList = new FieldList();
 fieldList.Add(linkFieldId, fakeLinkField.ToString());

 FakeItem contenItem= new FakeItem(fieldList);

 MediaManager.GetMediaUrl((MediaItem)((LinkField)contenItem.Fields[linkFieldId]).TargetItem).ShouldAllBeEquivalentTo("/~/media/hello.png");
 }

13-06-2013 13-14-53

Remember unlike other Sitecore unit testing examples this is all done i memory.  So this is pure unit testing no integration testing. And hopefully  Sitecore Fakes will develope over timer to support more features. Let me know which feature I should work on next.

Introducing Sitecore Fakes

07/06/2013 2 comments

Mocking Sitecore recently became a lot easier with Microsoft Fakes in Vs 2012 update 2 or by using Typemock. Lately I’ve started using NCrunh and yes it might be a bit overpriced but it is worth every penny, at least for me. I know Typmock work with NCrunch but that comes with an even larger price tag, and unfortunately Microsoft fakes doesn’t work “yet” with NCrunch, so I’m back to my Sitecore Test Item Orginal Post.

Earlier I showed how to stub out field data with the sitecore test item. With the test item you can cover the most basic data transfer stuff from Sitecore through the field collection. But I really wanted to do more complex testing without talking to the database or doing integrationtest. Mike Edwards showed a solution where you copy  sections from the web.config to a local app.config in your test project. By doing that you are doing more integration testing then unit ttestin.

So i wanted to find out how little you should copy from the web.config to make Sitecore test item now “FakeItem” extend more Sitecore functionality, for example Item.Children.

So i found by some investigation that the minimal configuration required to query the dataprovider is as follows

  <configSections>
    <section name="sitecore" type="Sitecore.Configuration.ConfigReader, Sitecore.Kernel" />
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, Sitecore.Logging" />
  </configSections>
  <sitecore database="SqlServer">
    <settings>
      <setting name="LicenseFile" value="D:\license.xml" />
    </settings>
  </sitecore>
  <log4net>
  </log4net>

Note that the path for the license file i absolute,

Now the problem is when asking for the ChildList through the Children Property you end up deep down in a provider instantiate by the ItemManager.  The default provider for some reason requires a valid licens. But with a valid license file now in place, what is next?

Why not replace the default Provider for the itemManager with a fake one, where we can control what to return for different calls to the Provider through the ItemManager.

<itemManager defaultProvider="default">
  <providers>
    <clear />
    <add name="default" type="Sitecore.Fakes.FakeItemProvider,Sitecore.Fakes" />
   </providers>
</itemManager>

and the complete configuration is now as follows

<configSections>
 <section name="sitecore" type="Sitecore.Configuration.ConfigReader, Sitecore.Kernel" />
 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, Sitecore.Logging" />
</configSections>
<sitecore database="SqlServer">
  <itemManager defaultProvider="default">
    <providers>
      <clear />
       <add name="default" type="Sitecore.Fakes.FakeItemProvider,Sitecore.Fakes" />
    </providers>
  </itemManager>
 <settings>
   <setting name="LicenseFile" value="D:\license.xml" />
 </settings>
</sitecore>
 <log4net>
 </log4net>

And my i present the new FakeItemProvider. And luckily Sitecore finally found good use of virtual methods.

public class FakeItemProvider : ItemProvider
{
 public override ChildList GetChildren(Item item, SecurityCheck securityCheck)
 {
    return new ChildList(item,((FakeItem)item).FakeChildren);
 }

 public override Item GetParent(Item item, SecurityCheck securityCheck)
 {
    return ((FakeItem) item).FakeParent;
 }
}

The fake itemprovider  depend on the FakeItem which I have extended a bit so it is possible to  add children and parents to an item. Off course this should be extended even more to support more Sitecore functionality.

 public class FakeItem : Item
 {
   public FakeItem(FieldList fieldList, string itemName = "FakeItem")
     : base(
    new ID(new Guid()),
    new ItemData(new ItemDefinition(new ID(new Guid()), itemName, new ID(new Guid()), new ID(new Guid())),
    Globalization.Language.Invariant, new Data.Version(1), fieldList),
    new Database("web"))
   {
     FakeChildren = new ItemList();
   }

  public void AddChild(Item child)
  {
   ((FakeItem) child).FakeParent = this;
    FakeChildren.Add(child);
  }

  public virtual Item FakeParent { get; set; }
  public virtual ItemList FakeChildren { get; set; }
 }

An example that shows the childList  and parent stub in action.

 public class FakeItemProviderTests
 {

   [Fact]
   public void FakeItem_AddMultipleChildren_ChildListShouldHaveAllChildren()
   {
    Item child = new FakeItem(new FieldList());
    FakeItem fake = new FakeItem(new FieldList());
    fake.AddChild(child);
    fake.AddChild(child);
    fake.AddChild(child);
    fake.AddChild(child);
    fake.AddChild(child);

    fake.Children.Should().HaveCount(5);
   }

  [Fact]
  public void FakeItem_AddChildToChildren_ShouldReturnChild()
  {
    Item child = new FakeItem(new FieldList());
    FakeItem fake = new FakeItem(new FieldList());
    fake.AddChild(child);

    fake.Children.First().ShouldBeEquivalentTo(child);
  }

  [Fact]
  public void FakeItem_AddChildToChildren_ChildShouldHaveParent()
  {
    Item child = new FakeItem(new FieldList());
    FakeItem fake = new FakeItem(new FieldList());
    fake.AddChild(child);

    fake.Children.First().Parent.ShouldBeEquivalentTo(fake);
  }

 [Fact]
 public void FakeItem_AddChildToChildren_ChildShouldHaveParentWithId()
 {
   Item child = new FakeItem(new FieldList());
   FakeItem fake = new FakeItem(new FieldList());
   fake.AddChild(child);

   fake.Children.First().ParentID.ShouldBeEquivalentTo(fake.ID);
 }
}

The code for this is free to download and can be found on GitHub Sitecore.Fakes.

Let me know what the next thing you like to get stubbed should be !

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.

Sitecore MVC new Ninject Controller Factory – clean version

23/10/2012 2 comments

In this post we will have  revisit my last blog post, using Ninject with Sitecore MVC. In this new approach we will simplify the code to do the exactly same thing as in the last post LINK.
So what we want is to be able to inject Concrete implementation in the our Sitecore Controller.
We will do this by creating a ninjectc controller factory and forwarding  to the default Sitecore controller factory, so our implementation is used when Sitecore creates it’s controller. By doing it this way all standard Sitecore MVC functionality will still work, but we now have the possibility to inject our concrete implementation on creation time of the controllers.

First we need a Factory for creating the Ninject kernel


 public class NinjectKernelFactory
 {
   public IKernel Create()
   {
    return LoadAssembliesIntoKernel(new StandardKernel());
   }

   private IKernel LoadAssembliesIntoKernel(IKernel kernel)
   {
     foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
     {
      try
      {
        kernel.Load(assembly);
      }
      catch (Exception)
      {
         //Empty Catch used because ninject have problem
         //with loading some of the Sitecore MVC assemblies.
        // Method .ToString()
      }
    }
     return kernel;
   }
 }

With that in place we can create the the NinjectControllerFactory


 public class NinjectControllerFactory : DefaultControllerFactory
 {

  private IKernel _kernel;
  public NinjectControllerFactory(IKernel kernel)
  {
    _kernel = kernel;
  }

  public override void ReleaseController(IController controller)
  {
    _kernel.Release(controller);
  }

  protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
  {
    return (IController)_kernel.Get(controllerType);
  }
 }

]

All that is left is now for binding it all together in a new InitilizeContollerFactory


 public class InitializeNinjectControllerFactory
 {
   public virtual void Process(PipelineArgs args)
   {
    SetControllerFactory(args);
   }

  protected virtual void SetControllerFactory(PipelineArgs args)
  {
    NinjectKernelFactory kernelFactory = new NinjectKernelFactory();
    NinjectControllerFactory ninjectControllerFactory = new NinjectControllerFactory(kernelFactory.Create());
    SitecoreControllerFactory sitecoreControllerFactory = new SitecoreControllerFactory(ninjectControllerFactory);
    ControllerBuilder.Current.SetControllerFactory(sitecoreControllerFactory);
  }
 }

And off course we need to swap the originale InitlizeControllerFactory with our new one.

Sitecore default :

</pre>
<processor type="Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc"/>

Replaced with this:


<processor type="SitecoreNinjectModule.InitializeNinjectControllerFactory, SitecoreNinjectModule"/>

Now Lets try it our I have created a really simple example first an Item with a controller rendering on.

And the sourcode for the controller


public class StoryController : SitecoreController

{
 private ITestInterface _testInterface;
 public StoryController(ITestInterface testInterface)
 {
 _testInterface = testInterface;
 }

public ActionResult From()
 {

ViewBag.Froms = _testInterface.Get();
 return View();
 }
 }

And now to the View Code

And our RazerView


@model dynamic
 <h2>From vIew</h2>

@ViewBag.Froms

And a simple TestInterface and TestClass


public interface ITestInterface
 {
 string Get();
 }


public class TestClass : ITestInterface
 {
 public string Get()
 {
 return "Hallo From Test";
 }
 }

And the output of it all

There we are a much nicer and cleaner solution presented then I came up with in my last blog post and without breaking any Sitecore functionalit, and off course you can still unit test the controller.

Sitecore MVC Ninject controller

17/09/2012 7 comments

This is last post in the series of three. As promised in my last post we will inject a repository through the construct in the controller. To do this we will use the Ninject as our IOC container, This will be a very quick walkthrough.

Also we to make it a bit easier to find controller that needs to have class’ injected we will create a derived class from the controller class’,

    public class NinjectController : Controller
    {}

Some of the assmeblies in sitecore mvc solution gives and error when trying to reflect upon them so there are a couple of catch’s in the code to handle some minor bugs.

Next we will create our controller factory  wrapping the Sitecores standard factory. This new Ninject controller factory will for the controller that should be loaded is of type nijectcontroller instantiate the corresponding concrete type of the constructers parameters.. Also this class loads all the ninject binding. Maybe it’s not so nice that it has multiple responsibility but it is left out for an exercise to refactor the code so it conforms to SRP 🙂 .

public class NinjectInitializeControllerFacotry
{
  public virtual void Process(PipelineArgs args)
  {
    this.SetControllerFactory(args);
  }

  protected virtual void SetControllerFactory(PipelineArgs args)
  {
    NinjectControllerFactory controllerFactory = new     NinjectControllerFactory(ControllerBuilder.Current.GetControllerFactory());
    ControllerBuilder.Current.SetControllerFactory(controllerFactory);
  }
}

and the controller factory it self

  public class NinjectControllerFactory : SitecoreControllerFactory
  {
    public NinjectControllerFactory(IControllerFactory innerFactory) : base(innerFactory)
    {
    }

    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
      Assert.ArgumentNotNull(requestContext, "requestContext");
      Assert.ArgumentNotNull(controllerName, "controllerName");
      try
      {
         IController controller = ICreateController(requestContext, controllerName);
         return controller;
      }
      catch (Exception exception)
      {
        if (!MvcSettings.DetailedErrorOnMissingController)
        {
          throw;
        }
        return new ErrorHandlingController(controllerName, exception);
     }
   }

   public override void ReleaseController(IController controller)
   {
    var disposable = controller as IDisposable;

    if (disposable != null)
    {
      disposable.Dispose();
    }
  }

  private IController ICreateController(RequestContext requestContext, string controllerName)
  {
    string fullControllerName = string.Format("{0}Controller", controllerName);
    Type ninjectController = FindSpecificNinjectController(fullControllerName);
    if (ninjectController != null)
    {
      return (IController)Kernel.Get(ninjectController);
    }
    return base.CreateController(requestContext, controllerName);
  }

  private Type FindSpecificNinjectController(string controllerName)
  {
    IEnumerable<Type> ninjectControllers = GetNinjectControllers();
    if(ninjectControllers.Any())
    {
     Type selectedNincjectController = ninjectControllers.FirstOrDefault(controller => controller.Name == controllerName);
     if (selectedNincjectController != null)
     return selectedNincjectController;
   }
   return null;
  }

 private IEnumerable<Type> GetNinjectControllers()
 {
    List<Type> types = new List<Type>();
    foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
    types.AddRange(FindDerivedTypes(assembly, typeof(NinjectController)));
    return types;
 }
 private IEnumerable<Type> FindDerivedTypes(Assembly assembly, Type baseType)
 {
   try
   {
    return assembly.GetTypes().Where(t => baseType.IsAssignableFrom(t));
   }
   catch (Exception)
   {
    return new List<Type>();
 }
 }

  private static IKernel _kernel;
  private IKernel Kernel
  {
   get
   {
    if (_kernel == null)
      CreateKernel();
     return _kernel;
    }
 }

protected void CreateKernel()
 {
   _kernel = new StandardKernel();
    foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
   {
    if (HasNinjectModules(assembly))
    _kernel.Load(assembly);
  }
 }

public static bool HasNinjectModules(Assembly assembly)
 {
   Type baseType = typeof (NinjectModule);
   try
   {
    return assembly.GetTypes().Any(t => baseType.IsAssignableFrom(t));
   }
  catch (Exception)
  {
    return false;
  }
  }
}

So all that is left is to overwrite the standard controller factory.


<initialize>
 <processor type="SitecorePresentation.SitecoreMVCRoutes,SitecorePresentation">
 <mvcIgnoreHomePage>false</mvcIgnoreHomePage>
 </processor>
 <processor type="Sitecore.Mvc.Pipelines.Loader.InitializeGlobalFilters, Sitecore.Mvc"/>
 <processor type="SitecoreMVCNinjectExtension.NinjectInitializeControllerFacotry, SitecoreMVCNinjectExtension"/>
 <!--<processor type="Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc"/>-->
 <processor type="Sitecore.Mvc.Pipelines.Loader.InitializeRoutes, Sitecore.Mvc"/>
 </initialize>

Next we can rewrite the controller from the last episode to conform to the new ninjectcontroller


public class NinjectItemController : NinjectController
 {
 private readonly IChildItemRepository _childItemRepository;
 public NinjectItemController(IChildItemRepository childItemRepository)
 {
 _childItemRepository = childItemRepository;
 }

public JsonResult Index(string id)
 {
 return Json(CreateObject(_childItemRepository.Get(id)), JsonRequestBehavior.AllowGet);
 }

&nbsp;

private IEnumerable<object> CreateObject(IEnumerable<Item> items)
 {
 List<object> objectList = new List<object>();
 foreach (Item item in items)
 objectList.Add(new { item.Name });
 return objectList;
 }

}

The repositories from the last post looks the samen but are listed below.

</pre>
public interface IChildItemRepository
{
IEnumerable<Item> Get(string parentItemId);
}
<pre>
</pre>
public class ChildItemRepository : IChildItemRepository
{
public virtual IEnumerable<Item> Get(string parentItemId)
{
ID parentId;
if(ID.TryParse(parentItemId,out parentId))
return GetChildNodes(parentId);
return new List<Item>();
}

private IEnumerable<Item> GetChildNodes(ID parentId)
{
Item parentItem = Sitecore.Context.Database.GetItem(parentId);
return parentItem.GetChildren();
}
}

Now to ninject magic the ninject module that factory are loading bindings from.


public class ChildItemRepositoryNinjectModule : NinjectModule
{
public override void Load()
{
Bind<IChildItemRepository>().To<ChildItemRepository>();

}
}

And of course now we can rewrite out unittest to test the new controller.


public class ItemControllerTest
 {
 [Test]
 public void ItemControllWithNoIdShouldReturnEmptyList()
 {
 IChildItemRepository childItemRepositoryStub = Substitute.For<IChildItemRepository>();
 childItemRepositoryStub.Get(Arg.Any<string>()).Returns(new List<Item>());
 NinjectItemController controller = new NinjectItemController(childItemRepositoryStub);

 JsonResult result = controller.Index(string.Empty);
 Assert.That(result.Data,Is.Empty);
 }

[Test]
 public void ItemControllWithInvalideIDShouldReturnEmptyList()
 {

IChildItemRepository childItemRepositoryStub = Substitute.For<IChildItemRepository>();
 childItemRepositoryStub.Get(Arg.Any<string>()).Returns(new List<Item>());
 NinjectItemController controller = new NinjectItemController(childItemRepositoryStub);
 JsonResult result = controller.Index("invalidID");
 Assert.That(result.Data, Is.Empty);
 }

[Test]
 public void ItemControllWithValidIdShouldReturnJsonListWithItemNames()
 {
 IChildItemRepository childItemRepositoryStub = Substitute.For<IChildItemRepository>();
 List<Item> childList = new List<Item>();

 childList.Add(new ItemStub("stub-a"));
 childList.Add(new ItemStub("stub-b"));
 childList.Add(new ItemStub("stub-c"));
 childList.Add(new ItemStub("stub-d"));

Guid itemGuid = Guid.NewGuid();
 childItemRepositoryStub.Get(itemGuid.ToString()).Returns(childList);
 NinjectItemController controller = new NinjectItemController(childItemRepositoryStub);
 JsonResult result = controller.Index(itemGuid.ToString());

List<object>resultData = (List<object>) result.Data; ;
 Assert.AreEqual(4,resultData.Count());
 Assert.AreEqual(resultData[0].ToString(),"{ Name = stub-a }");
 Assert.AreEqual(resultData[1].ToString(), "{ Name = stub-b }");
 Assert.AreEqual(resultData[2].ToString(), "{ Name = stub-c }");
 Assert.AreEqual(resultData[3].ToString(), "{ Name = stub-d }");
 }
 }

The import thing about the rewrite of the test are the ugly SET on the itemctroller is removed as the repository is passed in as contructor argument.The result from the test

As a last service the image below shows the file structure in visual studio .

Thats all, now we can create easy to test controllers using a repository pattern.

Unit testing our MVC Controller for Sitecore

10/07/2012 Leave a comment

Is this post and as promised, we will unit test the controller we created in the last post.
So we will rewrite the controller a tiny little bit, so we can inject a child item repository, ie. creating a stub for the repository. Since Sitecore as default doesn’t ship with ControllerFactory where it is possible use dependency inject we will rewrite the controller instead, so it has a default repository it uses when Sitecore is instantiating the controller, and one it uses when testing, or more precisely you can pass one in to Repository property. The updated controller code is listed below. In my next post we will extend Sitecore so we can inject class through the contructor with dependency Inject using Ninject.

public class ItemController : Controller
{
private IChildItemRepository _childItemRepository;

public JsonResult Index(string id)
{
return Json(CreateObject(ChildItemRepository.Get(id)), JsonRequestBehavior.AllowGet);
}
public IChildItemRepository ChildItemRepository
{
get { return _childItemRepository ?? (_childItemRepository = new ChildItemRepository()); }
set { _childItemRepository = value; }
}

private IEnumerable<object> CreateObject(IEnumerable<Item> items)
{
List<object> objectList = new List<object>();
foreach (Item item in items)
objectList.Add(new { item.Name });
return objectList;
}

}

Now the three test cases
1. No id supplied the controller should return an empty result.
2. Supplied  with an invalide Guid the controller should return an empty result.
3. Supplied with a valid guid, the controller should return a JSon result with  the item names for all child items placed under the node with specified Guid,

Now for the Unit test class, as a mocking framework I’ve used NSubstitute. I’ve used the ItemStub I did in the this post Unit testing with Sitecore Item.  The code for this test Item is also as a service listet below.

public class ItemStub : Item
{
public ItemStub(string itemName)
: base(ID.NewID, new ItemData(new ItemDefinition(ID.NewID, itemName, ID.NewID, ID.NewID),Sitecore.Globalization.Language.Invariant, new Sitecore.Data.Version(1), new FieldList()), new Database("dummy"))
{
}

}

[TestFixture]
 public class ItemControllerTest
 {
 [Test]
 public void ItemControllWithNoIdShouldReturnEmptyList()
 {
 IChildItemRepository childItemRepositoryStub = Substitute.For<IChildItemRepository>();
 childItemRepositoryStub.Get(Arg.Any<string>()).Returns(new List<Item>());
 ItemController controller = new ItemController();
 controller.ChildItemRepository = childItemRepositoryStub;
 JsonResult result = controller.Index(string.Empty);
 Assert.That(result.Data,Is.Empty);
 }

[Test]
 public void ItemControllWithInvalideIDShouldReturnEmptyList()
 {

IChildItemRepository childItemRepositoryStub = Substitute.For<IChildItemRepository>();
 childItemRepositoryStub.Get(Arg.Any<string>()).Returns(new List<Item>());
 ItemController controller = new ItemController();
 controller.ChildItemRepository = childItemRepositoryStub;
 JsonResult result = controller.Index("invalidID");
 Assert.That(result.Data, Is.Empty);
 }

[Test]
 public void ItemControllWithValidIdShouldReturnJsonListWithItemNames()
 {
 IChildItemRepository childItemRepositoryStub = Substitute.For<IChildItemRepository>();
 List<Item> childList = new List<Item>();

childList.Add(new ItemStub("stub-a"));
 childList.Add(new ItemStub("stub-b"));
 childList.Add(new ItemStub("stub-c"));
 childList.Add(new ItemStub("stub-d"));

Guid itemGuid = Guid.NewGuid();
 childItemRepositoryStub.Get(itemGuid.ToString()).Returns(childList);
 ItemController controller = new ItemController();
 controller.ChildItemRepository = childItemRepositoryStub;
 JsonResult result = controller.Index(itemGuid.ToString());

List<object>resultData = (List<object>) result.Data; ;
 Assert.AreEqual(4,resultData.Count());
 Assert.AreEqual(resultData[0].ToString(),"{ Name = stub-a }");
 Assert.AreEqual(resultData[1].ToString(), "{ Name = stub-b }");
 Assert.AreEqual(resultData[2].ToString(), "{ Name = stub-c }");
 Assert.AreEqual(resultData[3].ToString(), "{ Name = stub-d }");
 }

And a screenshot of the test status.

I know that there probably exists better ways to test json results, but it is out of scope for this post, and yes if it should be “clean tests” each test should only contain one assert, but is left for as an exercise for you :).

In the next post we will extend Sitecore so that we can create Controllers through dependency injection, with Ninject as an IoC container. With this solution we don’t need the ugly Set in the Repository Property.