Archive

Posts Tagged ‘C#’

Easy unit testing in Sitecore with AutoFixture, NSubstitute and Xunit

03/04/2017 Leave a comment

Unit testing Sitecore code has been around for quite som years now, and with the release of version 8.2 Sitecore has implemented a lot of new abstractions, which makes testing of Sitecore code easier. So if you not on 8.2 yet this might not be for you, or this could be a reason for upgrading to 8.2. Today there exists a couple of framework that will help developers with writing unit test to Sitecore one of the more known ones I Sitecore FakeDb. But as we shall see in the following a good portion of the more simple Sitecore API can easyli be test without, but creating test stubs can quick become a cumbersome tasks, and this is exactly where this post comes into play.

Let me briefly introduce AutoFixture

This is take from The AutoFixture Github pages https://github.com/AutoFixture/AutoFixture

AutoFixture is an open source library for .NET designed to minimize the ‘Arrange’ phase of your unit tests in order to maximize maintainability. Its primary goal is to allow developers to focus on what is being tested rather than how to setup the test scenario, by making it easier to create object graphs containing test data.

For me Autofixture helps me writing clean Tests where magic values, or test object are hidden away, ie dummy data is something created when the test runs. I strongly encourage you to take a deeper look at Autofixture it is an awesome Library

Okay so how does this combined with Xuint and NSubstitute. Today You can create an Subsitute for a Sitecore Item But it stille take quite som parameters to create the item so you need to create more than one Substitute see the example below.


  var db = Substitute.For<Database>();
  var itemId = ID.NewID;
  var language = Substitute.For<Language>();
  var definition = new ItemDefinition(
  itemId, "itemname", ID.NewID, ID.NewID);
  var data = new ItemData(
    definition, language,
    Sitecore.Data.Version.First, new FieldList());
  var item = Substitute.For<Item>(itemId, data, db);
  return item;

You could in your test have a test factory that just creates this object for you of course.

Enough Skip to the point .. okay lets see where you getting at.

Okay given the following class Which I want to test. All it does is, for the master database get the root item and add a ChildItem, with any TemplateId and return the newly created child.

public class MyClass
{
   private readonly IFactory _factory;
     public MyClass(IFactory factory)
     {
        _factory = factory;
     }

     public Item AddToSitecore()
     {
      Database database = _factory.GetDatabase("master");
      Item rootItem = database.GetItem("/sitecore/content/home");
      Item childItem = rootItem.Add("child", new TemplateID(ID.NewID));
      return childItem;
    }
}

I can write the following test

  using FluentAssertions;
  using NSubstitute;
  using Sitecore.Abstractions;
  using Sitecore.Data;
  using Sitecore.Data.Items;
  using Xunit;


namespace Sitecore.AutoFixture.NSubstitute
{
  public class MyClassTests
  {

   [Theory, AutoSitecoreData]
   public void MyClass_AddItemToWithAutoFixtureRoot_ShouldReturnItem(Item rootItem,Item childItem,Database database,IFactory factory)
   {
     //Arrange
     database.GetItem("/sitecore/content/home").Returns(rootItem);
     factory.GetDatabase("master").Returns(database);
     rootItem.Add(Arg.Any<string>(), Arg.Any<TemplateID>()).ReturnsForAnyArgs(childItem);
     MyClass sut = new MyClass(factory);

    //Act
    Item returnItem = sut.AddToSitecore();

   //Assert
   returnItem.Should().NotBeNull();
   returnItem.ID.Should().BeSameAs(childItem.ID);
   returnItem.Name.Should().BeEquivalentTo(childItem.Name);
   rootItem.Add(Arg.Any<string>(), Arg.Any<TemplateID>()).Received();
   database.GetItem("/sitecore/content/home").Received();

  }
 }
}

What is nice here is you can the easy created Database and Items (root,and child), and a Sitecore Factory, you can set your expectations in your own test to match what you’re testing.

All with the help of the  AutoSitecoreData Attribute that decorates the tests.

It magically creates new items, database, Sitecore factories, Settings, the last two fund in Sitecore Abstractions. No need for Factories, all you get is relevant data with out static items or

It’s not entirely magic, it extends some AutoFixture attributes, you can have a look at the code at Github

https://github.com/istern/Sitecore.AutoFixture.NSubstitute

 

There Are a few gotchas For this to work in your test, you need to get the code from Github  and build it, Hopefully I will soon build a nuget package which will make this step obsolete . But once build you can reference the SitecoreAutoDataAttribute in your tests. You will also have to reference Sitecore.Kernel but no additional references to Sitecore files is required.

Hope you will find this useful

Advertisements
Categories: Sitecore 8, Unit Testing Tags: ,

Unit testing in Sitecore 8.2

19/09/2016 Leave a comment

Sitecore has done a great job but abstracting a lot and marking a lot of methods as Virtual, take the Datbase class for instance it is now abstract class, and implement in the DefaultDatabase Also all methods in the Item class is now marked virtual. I must say I think It is great way Sitcore is heading, and they are doing great but allowing developers easly testing the code by taking the framework in this direction.

Ok,  but before I could also test using Microsoft Fakes, yes and there is Sitecore FakeDB, and also there was the old Framework I created myself Sitecore.Fakes, which didn’t work with sitecore 7+ because the Database contructer was made internal,  but now working again in 8.2, the latter two Framworks (Sitecore FAkeDB and Sitecore.Fakes) required additional setup in a App.config along with a license file in your Test project  With the changes mention before this is no longer required ..  I’ve updated the Sitecore.Fakes found here https://github.com/istern/Sitecore-Fakes the solution contains examples of how to test with this Framework, a simple example is given below.


[Fact]

public void NewFakeItemDefaultNameShouldBeFakeItem()

{

var fake = new FakeItem();

fake.Name.Should().Be("FakeItem");

}

Note I’ve trimmed the framework a lot, ie. removed functionality that will be rewritten., so it is no longer as feature rich as before but now working J, also it is by fare not as feature rich as Sitecore FakeDB.

Running Sitecore Field Editor from a Speak Command in Sitecore Experience editor Sitecore 8.1 Version

14/12/2015 Leave a comment

So with the release of sitecore 8.1 also came some minor changes to how the javascript are structured, this means that to run the Sitecore Field Editor from a Speak Command in Sitecore Experience editor, which i presented in this post, a minor changes is required. All that is needed to be changed is the way the reference to Experience editor is handled the full Javascript with the modification is show below.

define(["sitecore", "/-/speak/v1/ExperienceEditor/ExperienceEditor.js"], function (Sitecore, ExperienceEditor) {
    Sitecore.Commands.LaunchFieldEditor =
    {
        canExecute: function (context) {
            //YOU COULD ADD FUNCTIONALITY HERE TO SEE IF ITEMS HAVE THE CORRECT FIELDS
            return true;
        },
        execute: function (context) {
            // THIS IS FOR THE ALT TEXT ON IMAGE
            context.currentContext.argument = context.button.viewModel.$el[0].firstChild.alt;

            //THIS IS THE TOOLTIP ON LINK TAG "A"
            context.currentContext.argument = context.button.viewModel.$el[0].title;
            console.log(Sitecore);
            console.log(ExperienceEditor);
            ExperienceEditor.PipelinesUtil.generateRequestProcessor("ExperienceEditor.GenerateFieldEditorUrl", function (response) {
                var DialogUrl = response.responseValue.value;
                var dialogFeatures = "dialogHeight: 680px;dialogWidth: 520px;";
                ExperienceEditor.Dialogs.showModalDialog(DialogUrl, '', dialogFeatures, null);
            }).execute(context);

        }
    };
});

Only modification is the mapping of The Experience editor is now loaded with a direct link to ExperienceEditor.js Line 1.

Categories: C#, Javascript, Sitecore 8 Tags: , ,

Running Sitecore Field Editor from a Speak Command in Sitecore Experience editor

02/03/2015 16 comments

This post is an update of an old post https://blog.istern.dk/2012/05/21/running-sitecore-field-editor-from-a-command/ . Sitecore 8 brought along speak and deprecated the old solution presented in that blog post. So let’s speakify it and create a  new solution. Luckily Alister Berry provided an excellent blog post about creating simple custom ribbon in the experience editor http://www.programmingbynumbers.com/2015/01/31/creating-a-new-experience-editor-button-in-sitecore-8/ – So go read the post a comeback when your are done J.  For the rest of this post the button or functionality, if you like, will be to edit the HTML metatags ie. Title, meta-description, meta-keywords.

So let us begin with creating the button. Start Visual Studio launch the Sitecore Rocks and go to the Core database and navigated to “/sitecore/content/Applications/WebEdit/Ribbons/WebEdit/Page Editor” under the item create a new folder and the the newly created folder add a new Large button Fille out the fields as shown below.

01-1

 

01-2

 

01-3

 

 

So next step is to and a layout to the new button select the button and choose “Design layout” in Sitecore Rocks – shortcut “ctrl + u”, and choose and a new rendering “Large Button”

 

01-4

 

01-5

 

 

01-6

 

Next lets add the properties required for the solution to work

The properties are Click is “trigger:button:click”, Command “LaunchFieldEditor”, PageCodeScriptFileName : “PATH TO THE JS FILE WE CREATE NEXT”

01-7

 

 

01-8

 

 

Okay now we need to create PageCodeScriptFile:

define([&quot;sitecore&quot;], function (Sitecore) {

Sitecore.Commands.LaunchFieldEditor =
{
canExecute: function (context) {
//YOU COULD ADD FUNCTIONALITY HERE TO SEE IF ITEMS HAVE THE CORRECT FIELDS
return true;
},
execute: function (context) {
///CHOOSE YOUR OPTION BELOW

// THIS IS FOR THE ALT TEXT ON IMAGE
context.currentContext.argument = context.button.viewModel.$el[0].firstChild.alt;

//THIS IS THE TOOLTIP ON LINK TAG &quot;A&quot;
context.currentContext.argument = context.button.viewModel.$el[0].title;

Sitecore.ExperienceEditor.PipelinesUtil.generateRequestProcessor(&quot;ExperienceEditor.GenerateFieldEditorUrl&quot;, function (response) {
var DialogUrl = response.responseValue.value;
var dialogFeatures = &quot;dialogHeight: 680px;dialogWidth: 520px;&quot;;
Sitecore.ExperienceEditor.Dialogs.showModalDialog(DialogUrl, '', dialogFeatures, null);
}).execute(context);

}
};
});

Rather simple file which calls some server side code.  Also note that the settings will be save to the item when the ok button is clicked right away not need to click the save button in the experience editor.


public class GenerateFieldEditorUrl : PipelineProcessorRequest&lt;ItemContext&gt;
{
public string GenerateUrl()
{
var fieldList = CreateFieldDescriptors(RequestContext.Argument);
var fieldeditorOption = new FieldEditorOptions(fieldList);
//Save item when ok button is pressed
fieldeditorOption.SaveItem = true;
return fieldeditorOption.ToUrlString().ToString();
}

private List&lt;FieldDescriptor&gt; CreateFieldDescriptors(string fields)
{
var fieldList = new List&lt;FieldDescriptor&gt;();
var fieldString = new ListString(fields);
foreach (string field in new ListString(fieldString))
fieldList.Add(new FieldDescriptor(this.RequestContext.Item, field));
return fieldList;
}

public override PipelineProcessorResponseValue ProcessRequest()
{
return new PipelineProcessorResponseValue
{
Value = GenerateUrl()
};
}
}

Now lyou should  register the Request processor open the this file “Sitecore.ExperienceEditor.Speak.Requests.config” found in App_config/include folder. And add the new processor.

&lt;request name=&quot;ExperienceEditor.GenerateFieldEditorUrl&quot; type=&quot;PT.Framework.SitecoreEditor.GenerateFieldEditorUrl, PT.Framework.SitecoreEditor&quot;/&gt;

Just before we see the result there a few things that are nice to know. Because the server side code actually does a bit more the just returning and url for fieldeditor.  The creation of the URL Handle also besides creating a URL to the fieldeditor is storing required parameters in the current session in the urlhand id. The fieldeditor then pickups on parameters by going in to the session with hdl-id see url below. Hdl=F60F9A3AB4DC4CC8A7E28D25C4EC13B8

http://local/sitecore/shell/applications/field%20editor.aspx?mo=mini&amp;hdl=F60F9A3AB4DC4CC8A7E28D25C4EC13B8

Okay now to the tricky part we need to pass in which fields we want to edit to the server class GenerateFieldEditorUrl,  unfortunately the parameter part of the layout isn’t rendered out and can’t be used but there are som simple ways we can force the fieldnames out in the HTML.

First you can edit the button item and set in the fieldnames in n the tool tips section

 

01-9

 

Alternatively you can set it in layout details page under tooltips, Be advised that if you choose this, editor will see the fieldname in the editors.

 

01-10

 

 

See the two different models below. The javascript in this post include selector for both option see comments in the js file

 

 

 

01-11
01-20

 

And now to the final result


01-14

 

 

So thats how you laucnh the field editor with a speak modal dialog, in the sitecore experience editor.

 

 

UPDATE 1
A problem with the two selector presented above is that they both requires you to add the fields to all language versions of the button item. So one of collegues Stephan Rifbjeg came up with a smart solution, simply to add the fields to the acceskey field on the layout see image below.

2015-03-04_09-15-14

You can now get the value out with the following selector

context.currentContext.argument = context.button.viewModel.$el[0].accessKey;

Update from  kayeenl to catch the GenerateFieldURI


public class GenerateFieldEditorUrl : PipelineProcessorRequest<ItemContext>
{
public string GenerateUrl()
{
var fieldList = CreateFieldDescriptors(RequestContext.Argument);
var fieldeditorOption = new FieldEditorOptions(fieldList);
//Save item when ok button is pressed
fieldeditorOption.SaveItem = true;
return fieldeditorOption.ToUrlString().ToString();
}<span class="para_break"><i class="copy_only">
</i></span>       private List<FieldDescriptor> CreateFieldDescriptors(string fields)
{
var fieldList = new List<FieldDescriptor>();
var fieldString = new ListString(fields);
foreach (var field in new ListString(fieldString))
{
try
{
var descriptor = new FieldDescriptor(RequestContext.Item, field);
fieldList.Add(descriptor);
}
catch (Exception)
{
Log.Error(string.Format("Cannot create field editor for field '{0}'. Please configure the fields on the tooltip of the button", field), this);
}
}
return fieldList;
}<span class="para_break"><i class="copy_only">
</i></span>       public override PipelineProcessorResponseValue ProcessRequest()
{
return new PipelineProcessorResponseValue
{
Value = GenerateUrl()
};
}

WFFM publishing with related item, fixing missing form elements

29/10/2014 2 comments

When adding a form to a page via the page editor, Sitecore registers a reference to form element, so when you publish you can check the publish related Items checkbox, and you would expect the form to be visible on your CD-server

29-10-2014 11-22-29

However WFFM places all elements in the form as children to form element itself, and these are not added to the publishing queue because they are not related to page where the form was first added.

29-10-2014 11-23-32

So when publishing the form is correctly being published, but the fields for the forms isn’t moved from the master database to web database and the form is of course then not rendered out.

As always Sitecore has a pipeline, that you can hook into in this case the “getItemReferences” this pipelines, resolves related items and adds them to the publishing queue. So hooking into this and adding child elements for forms is actually quite easy.


public class GetFormChildElementProcessor : GetItemReferencesProcessor
{
  private readonly ID _formTemplateId = new ID("{FFB1DA32-2764-47DB-83B0-95B843546A7E}");
 protected override List<Item> GetItemReferences(PublishItemContext context)
 {
  List<Item> relatedformItems = new List<Item>();
  if(!context.Result.ReferredItems.Any())
   return relatedformItems;
  Database database = context.PublishContext.PublishOptions.SourceDatabase;
  var formItems = context.Result.ReferredItems.Where(i=>IsDerived(database.GetItem(i.ItemId).Template, _formTemplateId)).ToList();

  foreach (var form in formItems)
  {
    var formChildren = form.ChildEntries;
    foreach (var child in formChildren)
    {
      relatedformItems.Add(database.GetItem(child.ItemId));
    }
  }
  return relatedformItems;
}

 public bool IsDerived(TemplateItem template, ID templateId)
 {
  if (!(template.ID == templateId))
  {
   return Enumerable.Any<TemplateItem>(template.BaseTemplates, baseTemplate => IsDerived(baseTemplate,templateId));
  }
   return true;
 }
}

And now register the processor in the web.config  under /configuration/sitecore/pipelines/getItemReferences add it at the end.

<processor type="PT.Framework.PublishForm.GetFormChildElementProcessor, PT.Framework.PublishForm"/>

Now all the child elements to items the derives from the form element will be added to the publishing queue.

Categories: C#, Sitecore, WFFM Tags: , ,

Escaping dashes/“-” in Sitecore Queries. Datasource query Update

29/10/2014 5 comments

This is actually more an update to the post Query in Datasource location I wrote some while ago. As I was working on a new solution I often saw an error with “unterminated literal string in Query”. In my case it was actually quite simple because an item name include a dash “-”, which is an illegal character  in a query, the solution is to escape the part of the the path that contains  the “-”.  you escape it by adding “#” around the word, see the example below. 

query:/sitecore/content/some/path-with-dash/becomes 

query:/sitecore/content/some/#path-with-dash#/becomes

 The code to fix this is simple and Anders Laub wrote the version you see below.


private string EscapeItemNamesWithDashes(string queryPath)
{
  if (!queryPath.Contains("-"))
   return queryPath;

  var strArray = queryPath.Split(new char[] { '/' });
  for (int i = 0; i < strArray.Length; i++)
  {
    if (strArray[i].IndexOf('-') > 0)
    strArray[i] = "#" + strArray[i] + "#";
  }
  return string.Join("/", strArray);
}

 

The source code for using queries is also available on github , with the above enhancement.

https://github.com/istern/RenderingsDatasources

 

 

Categories: C#, Sitecore Tags: , ,

Launch Mongo DB with Sitecore Pipelines

01/10/2014 2 comments

My  colleague Brian Pedersen recently wrote at blog post about setting up MongoDB and starting it up with a simple bat-file read it here

http://briancaos.wordpress.com/2014/10/01/sitecore-and-xdb-setting-up-mongodb-on-your-developer-machine/

Combine the first step “download” mongo with starting a process as my other colleague Anders Laub showed how to do in his crush png post here http://laubplusco.net/crush-png-in-sitecore/

 

Then you have a pipeline that can start mongo if it isn’t running.

First lets create a new custom pipeline to start a mongo instance if none  is running

First the new “startmongodb” pipeline

<startmongodb>
  <processor type="Mongo.PingMongoDB, Mongo" />
  <processor type="Mongo.StartMongoDB, Mongo" />
</startmongodb>

  Replace string constant with more generic method, First a processor that test to see if mongo is allready running.

   public class PingMongoDB
    {
        public void Process(PipelineArgs args)
        {
            Log.Audit("Pinging Mongo", this);
            //Replace with connectionstring from config file
            var client = new MongoClient("mongodb://localhost");

           var server = client.GetServer();

            try
            {
              server.Ping();
              Log.Audit("Mongo Allready running", this);
              args.AbortPipeline();
            }
            catch (Exception)
            {
                Log.Audit("Mongo Not Running", this);
            }
        }
    }

 Now to the start mongo processor 

    public class StartMongoDB
    {
        public void Process(PipelineArgs args)
        {
            var startInfo = new ProcessStartInfo
            {
                CreateNoWindow = true,
                UseShellExecute = false,
                //Replace with path to  your mongo
                FileName = "D:\\MongoDB\\bin\\mongod.exe",
              //Replace with path to  your mongo datadrive
                Arguments = @"--dbpath sc75rev140429\Databases\MongoDBData",
                WindowStyle = ProcessWindowStyle.Hidden
            };
            try
            {
                Log.Audit("Trying to start mongo",this);
                using (var exeProcess = System.Diagnostics.Process.Start(startInfo))
                {
                    exeProcess.WaitForExit(50);
                }
                Log.Audit("Mongo started", this);
            }
            catch (Exception exception)
            {
                Log.Error("Could not start mongo", exception, this);
            }
        }
    }

 

Finally we need to run the “startmongodb” pipeline when Sitecore Starts/Initialize so in

the initialize pipeline and at the end add 

<processor type="Mongo.RunMongoPipeline, Mongo" />

code for this simple processor

public class RunMongoPipeline
    {
        public void Process(PipelineArgs arg)
        {
            CorePipeline.Run("startmongodb",new PipelineArgs());
        }
    }

From the log we can now see if mongo isn’t runnnig and was started also there is now warnings in the log :
INFO AUDIT (default\Anonymous): Mongo Not Running
INFO AUDIT (default\Anonymous): Trying to start mongo
INFO AUDIT (default\Anonymous): Mongo started

so the follwing isn’t seen in the log which it would be if mongo wasn’t running

ERROR MongoDbDictionary.Store() has failed.
Exception: Sitecore.Analytics.DataAccess.DatabaseNotAvailableException
Message: Database not available
Source: Sitecore.Analytics.MongoDB
   at Sitecore.Analytics.Data.DataAccess.MongoDb.MongoDbCollection.Execute(Action action, ExceptionBehavior exceptionBehavior)
   at Sitecore.Analytics.Data.DataAccess.MongoDb.MongoDbDictionary.Store(Object value)

What is left now is cleaning the code and use args for supplying the correct values instead of hardcoded strings. This is left as a free of charge  excercise.

Categories: C#, MongoDB, Sitecore Tags: , ,