Archive

Archive for the ‘Sitecore Fakes’ 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

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.