Archive

Archive for September, 2008

Automated Testing and Sitecore – Part 3

September 30, 2008 2 comments

In my first post of this series I talked about the high level concepts of how I do my automated testing in Sitecore. All of the techniques I wrote about require a known content structure to test against as the content tree makes up one part of the input into our test. This post is going to focus on programatically setting up our test environment so we can perform our tests in a repeatable automated fashion.

So lets talk about the content tree as input to our test. To gain a good coverage and confidence with our tests we need to test our Sitecore components with expected content, unexpected content, missing content, etc. And we should be good citizens and ensure that once our tests are complete we destroy any test data (out test content items).

Let’s start with the basics of creating items programatically. When we create an item in Sitecore we create it under an existing item. We are also required to create the item based on a template. So the first thing we need to do is get a reference to the parent of where we want to create our content.

Sitecore.Data.Items.Item parent = 
  Sitecore.Context.Database.GetItem("/sitecore/content/testhome");

Next we’ll find the template we wish to use. You need to have created this template ahead of time. This template will most likely be from your current project / implementation.

Sitecore.Data.Items.TemplateItem template = 
  Sitecore.Context.Database.GetTemplate("sample/sample item");

And now we can “add” our item below the parent we found.

Sitecore.Data.Items.Item myItem = parent.Add("MyItem", template);

I can now create more items either below my parent item or below the newly created item to have it nested. Using these methods I can easily create a test content tree. And of course we all know how to set the fields of the item.

using (new Sitecore.Data.Items.EditContext(myItem))
{
  myItem["title"] = "My New Item";
  myItem["custom field 1"] = "some value";
}

In the cleanup after our tests have completed we need to destroy our test items. It is much easier for our cleanup if we keep all our test nodes under a separate item such as the testhome item above. Then we just need to delete the children of that item to cleanup our content back to a clean state ready for the next test to be run.

parent.DeleteChildren();

That’s all the code we need to create and tear down our test content. So let’s put it all together. How we call the setup code will depend on what kind of test we’re running. If we’re running our tests inside the Sitecore context (such is the case with the custom test runner), then I can invoke the code directly. Just make sure you take into consideration the security of the running site. By default the test runner page will be running as the extranet\anonymous user. This user doesn’t have permission to create or edit content, so make sure before you perform any of these actions you wrap your code in a SecurityDisabler. I can then call this code from the test class setup and cleanup methods.

[TestFixtureSetUp]
public void TestFixtureSetUp()
{
  Sitecore.Data.Items.Item parent =
    Sitecore.Context.Database.GetItem("/sitecore/content/testhome");
  Sitecore.Data.Items.TemplateItem template =
    Sitecore.Context.Database.GetTemplate("sample/sample item");

  using (new Sitecore.SecurityModel.SecurityDisabler())
  {
    Sitecore.Data.Items.Item myItem = parent.Add("MyItem", template);
    using (new Sitecore.Data.Items.EditContext(myItem))
    {
      myItem["title"] = "My New Item";
      myItem["custom field 1"] = "some value";
    }

    Sitecore.Data.Items.Item myNestedItem = myItem.Add("My Nested Item", template);
    using (new Sitecore.Data.Items.EditContext(myNestedItem))
    {
      myNestedItem["title"] = "My Nested Item";
      myNestedItem["custom field 1"] = "Some kinda value";
    }

    Sitecore.Data.Items.Item myItem2 = parent.Add("MyItem2", template);
    using (new Sitecore.Data.Items.EditContext(myItem2))
    {
      myItem2["title"] = "My 2nd Item";
      myItem2["custom field 1"] = "some value 2";
    }
  }
}

[TestFixtureTearDown]
public void TestFixtureTearDown()
{
  Sitecore.Data.Items.Item parent =
    Sitecore.Context.Database.GetItem("/sitecore/content/testhome"); 
  using (new Sitecore.SecurityModel.SecurityDisabler())
  {
    parent.DeleteChildren();
  }
}

If my tests will run from within a different test host process such as when running from the Visual Studio test runner (VSUnit) then I won’t be able to call directly into the Sitecore API as I will be missing the Sitecore context. Instead I will create an environment setup page hosted inside Sitecore and make requests to this page to setup and destroy test items. The code of this page will run inside Sitecore and will have a Sitecore context available. This page doesn’t necessarily have to be a Sitecore presentation component such as a layout or sublayout. It can be a stand alone page. Being a stand alone page also makes it easier to identify the testing components for deployment and exclude them.

To initialise the content tree for a test I will make an HTTP request in my test setup to the test setup page. And likewise to cleanup after the tests have completed. I can do this using the WebRequest classes from the .net framework. I generally use a query string to determine the action to perform on the setup page. This technique can extend to include choosing a particular test content tree to setup. Each tree can exist in your test setup code as a separate method which is invoked depending on the query string.

Please note the following code is VSUnit.

using System.Net;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TestProject1
{
  [TestClass]
  public class UnitTest1
  {
    private TestContext testContextInstance;
    private static string m_url = "http://localhost/setup.aspx";

    public TestContext TestContext
    {
      get { return testContextInstance; }
      set { testContextInstance = value; }
    }

    [ClassInitialize()]
    public static void MyClassInitialize(TestContext testContext)
    {
      WebRequest request = WebRequest.Create(m_url + "?setup=content1");
      request.GetResponse();
    }

    [ClassCleanup()]
    public static void MyClassCleanup()
    {
      WebRequest request = WebRequest.Create(m_url + "?cleanup=yes");
      request.GetResponse();
    }
  }
}

And now I can write my tests certain that the content tree will be exactly as I expect. In the next post for this series, I will start testing some code written against the Sitecore API.

Categories: Sitecore

Into Shared Source

September 30, 2008 Leave a comment

It is with great pride I today became part of the elite known as the Sitecore shared source contributors. How does one become part of such a privileged group? You just have to contribute something to the Sitecore shared source repository :) . I have placed one of my Sitecore tweaks, the Editor Line Numbers which I released on this blog a few months ago, into Sitecore shared source.

I did this after Jimmie Overby contacted me after he saw my tweaks posted on my blog. I had been thinking of how I might contribute some of my tweaks into the shared source, but I didn’t see these things as requiring a great many updates and improvements that would engage community contributors. But Jimmie pointed out to me something that I already realised. The SDN is the central resource for all things Sitecore. Some people may stumble upon my blog, but more people will be frequenting SDN so there’s more chance of the community gaining benefit from my tweaks if they can reach them through this central channel.

And so for this reason I will be placing all my future Sitecore tweaks into shared source. If Jimmie doesn’t want them, then I’ll just put them on my website. I’m also currently working on moving the quick launch toolbar over to shared source as well.

You can now find the editor line numbers tweak on the SDN at http://sdn5.sitecore.net/Resources/Shared%20Source/Shell%20Extensions/Editor%20Line%20Number.aspx.

Categories: Sitecore

Automated Testing and Sitecore – Part 2

September 27, 2008 3 comments

In the first post of this series I mention I make use of a custom NUnit test runner which runs in the Sitecore context. In this post I’ll take you through creating such a test runner.

The test runner is just a web form deployed to the webroot of your Sitecore site. Because it runs inside your Sitecore application it runs within a Sitecore context.

The test runner allows running a selection of test categories from your test suite, so you don’t have to run all of your tests on each test run.

The first thing we need to do is create a test project to contain your NUnit tests and the test runner itself. Prior to Sitecore 6.0, Sitecore used to contain NUnit assemblies (and a test runner too) and I used to reference these. Unfortunately as of Sitecore 6.0 NUnit has been removed, so you’ll first have to go and download NUnit , then make references in your project to nunit.core, nunit.core.interfaces and nunit.framework.

Next, create a new web form which will be the test runner. In the code behind of this form implement the NUnit.Core.EventListener interface. The primary method I’m interested here is TestFinished, but you can use the others if you want to do some more advanced stuff with your test runner. TestFinished is called each time a test is, well, finished and it allows you to log statistics about the test and the tests outcome. Refer to the full code (link at the bottom of this post) to see how I collect this information.

Now we can load the test suite in the Page_Load method of the page. Add a using statement for NUnit.Core and System.Reflection in the code behind and declare a member variable to store the TestSuite in.

private TestSuite m_testSuite = null;

Then place the following code in the Page_Load method.

CoreExtensions.Host.InitializeService();
TestPackage pkg = new TestPackage(Assembly.GetExecutingAssembly().Location);
m_testSuite = new TestSuiteBuilder().Build(pkg);

The above assumes your tests will be located in the same assembly as the test runner. If they are not then you’ll have to pass the location of the test suite assembly to the TestPackage constructor. We can run the test suite by calling the Run method on the test suite.

TestResult result = m_testSuite.Run(this);

We can then inspect the result to see if we passed or not. That’s a simple test runner, but it won’t let us filter the tests to run, so the above code will be an all or nothing affair. To filter the tests which will be run there is an overload to the Run method which accepts an ITestFilter. The default filters can be found in the NUnit.Core.Filters namespace. I’ll use a category filter. This filter accepts the category names as a string to it’s constructor. But we don’t want to hard code any catgeory values, so we’ll need to read them out of the test suite assembly.

This sounds like it should be easier than it actually is. This is to to with the stucture of the test suite assembly and the objects NUnit exposes to us (or maybe I didn;t dig deep enough :) ). TestSuite contains an IList property called “Categories” which will list the categories for the current level. The thing is that the NUnit tests are heirarchical, so we’ll have to traverse each nested ITest from the TestSuite’s Tests property to generate a full list of all categories in the current test suite assembly. The following method will do this for you.

private void GetCategories(TestSuite suite, StringCollection cats)
{
  if (suite.Categories != null)
  {
    for (int i = 0; i < suite.Categories.Count; i++)
      if (!cats.Contains((string)suite.Categories[i]))
        cats.Add((string)suite.Categories[i]);
  }

  for (int i = 0; i < suite.Tests.Count; i++)
    if(((ITest)suite.Tests[i]).IsSuite)
      GetCategories((TestSuite)suite.Tests[i], cats);
}

To invoke it just pass it the current test suite and a string collection to populate. Once you have the list of categories you can list them on the web form in a check box list or similar, then construct a category filter from the selected categories before calling run.

You can use the above code examples to construct your own custom NUnit test runner or download the full source for my custom test runner from my website: http://users.tpg.com.au/adeneys/codenunitrunner.html

Categories: .net, Sitecore

Show some standard fields always

September 23, 2008 Leave a comment

I had a question posed to me today from Krystle Magadia from New Zealand about how to show some of the standard fields without having to switch on standard fields under the view tab in the content editor. The scenario given was that the archive and reminder fields (under the tasks field section) should always be displayed. Normally we interact with these fields using the commands and wizards on the content editors ribbon. Although I can see benefit of not having to click another button to quickly view the archive date for an item.

So how would I make a particular standard field display always? Checking in web.config we find that the inclusion of fields for display in the content editor is managed from a pipeline. This makes it very easy to hack (read: modify, update, alter). The pipeline name is “getContentEditorFields” and by default it contains a single processor; Sitecore.Shell.Applications.ContentEditor.Pipelines.GetContentEditorFields.GetFields.

<getContentEditorFields>
  <processor type="Sitecore.Shell.Applications.ContentEditor.
    Pipelines.GetContentEditorFields.GetFields, Sitecore.Client"/>
</getContentEditorFields>

Looking at the GetFields class, there is a virtual method called “CanShowField”. Being that this method is virtual, the developer intends for implementers to override this method when subclassing.

So I could just create a class which inherits from GetFields and just override the CanShowField method. This is too easy!

So for the example above where I always want to see the archive date field my custom class might look something like the following:

using Sitecore.Shell.Applications.ContentEditor.Pipelines.GetContentEditorFields;

namespace ContentEditorHacks
{
  public class CustomGetFields : GetFields
  {
    protected override bool CanShowField(Sitecore.Data.Fields.Field field,
      Sitecore.Data.Templates.TemplateField templateField)
    {
      if (field.ID == Sitecore.FieldIDs.ArchiveDate)
        return true;
      else
        return base.CanShowField(field, templateField);
} } }

So all I’m doing is checking the ID of the field being passed to me against the known field IDs in Sitecore. Returning true out of this method will add that field into the list of displayed fields.

The last step is just to update the pipeline to use my custom processor instead of the default one.

<getContentEditorFields>
  <processor type="ContentEditorHacks.CustomGetFields, ContentEditorHacks"/>
</getContentEditorFields>

And there we go. Open any item in the content editor and you’ll now see your standard field displayed even when not viewing with standard fields turned on in the view tab.

For a bit more info into the UI pipelines and the content editor, go check out Alexey Rusakov’s blog. He posted a few great pieces recently: The renderField Pipeline and Sitecore 6 Pipelines: renderItemTile. The latter describes how to add little indicator icons to existing item icons in the content editor.

Categories: Sitecore

Automated Testing and Sitecore – Part 1

September 19, 2008 14 comments

Well, my last post seems to have generated some interest. Automated testing with Sitecore is a hot topic. It is much more difficult and complex than those 2 second demos you see for general unit testing in your code. The purpose of this post is to describe how I currently perform my automated testing against Sitecore. I say currently because I am constantly updating how I do this as I discover better ways to test, and as people question me on my current processes. I encourage this questioning as it causes me to re-evaluate what I have established to make sure I am actually doing the best I can. And to this end, I encourage your comments if you think I’m totally off the mark.

So let me set a perspective for you. When you write code for Sitecore, you’re not writing standalone code. You’re writing a customisation for an existing system. How can I unit test customisation code for an external system? Well I just need to extract my code from that environment and test it in isolation. To do that I will probably need to mock a few things that my customisations are relying on. Like the Sitecore context. And therein lies the problem.

Sitecore is a complex system. I’m pretty sure I’ve got a good idea about how it works, and what I can expect when I call certain methods on certain classes and objects, but how can I be absolutely 100% sure? I started thinking about trying to mock Sitecore and it’s context so I could unit test one day, and after a lot of making my head hurt with the sheer amount I would have to mock, I pretty much gave up. I hold the opinion that you shouldn’t mock anything that you can’t ultimately change. Mocking is great for removing dependencies in a custom dev project for code that I can control and change. I should have absolute intimate knowledge of this code and how it MUST work. I can set the expectations quite easily. Not so with a 3rd party system. I can have a pretty good idea about how I think it should work, but ultimately I don’t think I ever have enough knowledge of it to properly mock it.

There might be some classes in Sitecore I might be able to mock easily. Can I mock an item? Can I mock a database? When I call GetItem on the Database class, I know I should expect these certain Items back as long as the items exist in the content tree, and are in a final workflow step, and don’t have any publishing restrictions, and a publish has occurred, and, and, and. Can you see where I’m headed here? Well perhaps I don’t care about all those things and I just want to test the case where my items defiantly are returned? Well maybe I could mock that. But when I started looking into it last time it would have taken a hell of a lot of effort to do so.

Instead, I made the realisation and admittence that you can’t unit test code written to customise a 3rd party system. I put the effort I would have spent trying to mock Sitecore into writing integration tests. When I’m testing code for Sitecore, I’m not unit testing. All my tests are integration tests, hence the title of this post. That’s why I call it automated testing, cause that’s what I’m more concerned with. Being able to repeat my tests at the click of a button rather than completely isolating my code under test. It’s not ideal, and as I said earlier, I’m constantly reassessing my testing techniques. I might spend the time one day to attempt to mock Sitecore to simplify my tests, but for now I’m happy to do integration rather than unit tests.

I wrote a custom NUnit test runner which is an ASP.NET page which runs my NUnit tests. The benefit of my custom test runner is that the test runner itself runs in the ASP.NET context and can be dropped into a Sitecore site, so now my test runner is running in the Sitecore context and I can call into the Sitecore API. There are many problems trying to use the Sitecore API from a console or windows app; I’m sure you’ve all tried :) .

Depending on what we’re testing will determine what kind of test I write. If I’m testing low level methods that use the Sitecore API, then I’ll write a standard NUnit test which runs in my custom test runner. If I’m testing a Sitecore web control (class which inherits from Sitecore.Web.UI.WebControl) then I’ll write a NUnit test to run in the custom test runner and call the RenderAsText method from my TestMethod. If I’m testing other page elements which generate markup and have no dynamic page behaviors I’ll use a test which doesn’t run in the custom test runner, and I’ll make an HTTP request to a page hosting the control under test, then use HTML Agility Pack to navigate the response and make my assertions on the markup. HTML Agility Pack is also used by Sitecore internally (check the bin folder). If I’m testing a control which does exhibit dynamic behaviors I’ll use WatiN to make the request as this will use IE and will run javascript. I’ll also use WatiN if I’m testing a form or anything else which requires more than just a request (like posting back).

In all cases I need to setup the content tree before my tests run, and pull it down after they run. I normally have a separate sub content subtree for each Test Fixture / Class. If my test is running in the Sitecore context, then I can call directly into the API to setup the test items, and also to delete them when done. If I’m calling from a separate test framework which doesn’t use my custom NUnit test runner, then I’ll do my creation and cleanup in a layout which is attached to a permanent item in the content tree. The query string I pass this item determines what action to take such as create test content 1, test content 2, etc or cleanup. That way, in my test setup all I have to do is make an HTTP request to the appropriate URL and the items required for test get created. Likewise, it’s just another HTTP request to cleanup when I’m done.

That explains my testing processes at a high level. Over the next few posts I’ll delve into how I actually do each of the different kinds of tests I mention above, and I’ll also include how to create the custom test runner.

Categories: .net, Sitecore

Damn you VSUnit!

September 14, 2008 4 comments

I ran into quite an unusual quirk with VSUnit today. (I’ve taken to calling Visual Studio Unit Testing VSUnit for brevity.) I’ve been doing some Sitecore dev using Test Driven Development (TDD) which I have had great success with in the past when working in a purely NUnit space. But with VSUnit I like the ability to run my tests straight inside the IDE (please don’t point me at TestDriven.net :) ). And also the integrated code coverage (please don’t point me at NCover). Yeah, I know there are things I can use with NUnit to give me these capabilities, but the VSUnit things requires no additional setup. It’s there out of the box.

So enough about the good points of VSUnit…onto the source of this rant. So, there are 2 buttons in the toolbar which allow me to either run the tests in the current context, or all tests in the project.

VSUnit toolbar

The tests in the current context depend where your cursor is. If your cursor is in the body of a test method, then only that single test will be run. If it’s in a test class file outside a method, then all the tests for that class will be run. But when I have several tests and test classes, I don’t want to execute each test class separately, I want to make use of that “run all tests in project” button.

So when I click to execute all tests in the project, what order did VS run them in? Almost random apparently. Hmm. I was expecting it to behave like NUnit, where if I select to run all tests they will run in some kind of predictable order. At least all the tests for a test class are executed one after another in NUnit. VSUnit runs them completely out of order. It might execute Class1.Test1 then Class1.Test2 then Class2.Test1 then back to Class1.Test3…Completely out of order. OK, I can see the point that unit tests should be isolated and atomic and should be able to be run in any order. And I agree. Test 3 should not rely on Test 1 being executed before it. But what about when I’m doing class initialisation and cleanup? I’ll get back to that in a second as it ties into my next rant.

So what happens if I need to perform class initialisation and cleanup. This is the perfect place to create the Sitecore items which are required by your tests, and then destroy them to return the environment to a known good state when our tests are complete. As anyone who has done this before, you’ll know that item creation in Sitecore is not cheap…it takes time. So we don’t really want to be creating and destroying items for each test. Now in NUnit, because everything runs in an order as I expect, I know that the class initialise will execute, then the classes tests, then the cleanup, then onto the next test class. Not so with VSUnit. It will call the classes initialise, then some of the tests, then it will branch off to another test. And if that test requires initialisation it will call that, then the test, etc. Note, we haven’t called any cleanup yet. VSUnit waits until all tests have completed before calling any of the cleanup methods. So in the case above where I create Sitecore items during initialisation and clean them up in cleanup, my items don’t get cleaned up before the next test class runs, so when it initialises it’s initialising into a dirty environment.

In the end I had to move my Class Init and Cleanup to Test Init and Cleanup. Looks like I might have to reassess the use of those other NUnit extensions for VS…

Categories: .net

Source Control for my content

September 5, 2008 Leave a comment

Sitecore already has version control built in for content. This is great when you’re using the CMS to deliver content, but during implementation the benefit isn’t as great. What would be really good, is if I could somehow utilise my existing source control software which I use for my developer files for the content as well.

Ah, Sitecore 6.0. With it’s wealth of new features and usability improvements has answered my prayers. But not before Revolver! Sitecore 6.0 introduced a new feature on the developer tab in the content editor which gives me the ability to serialize content items and subtrees from the content tree to files on disk. The items are serialized into a very light custom text format, not XML.

Revolver has allowed me to serialize items and trees to disk in their XML representations since before version 1.0 was released, and this is available for Sitecore 5.3.x and 6.0. The item serialization from the developer toolbar above is only available in Sitecore 6.0.

To use the content editor approach we first need to ensure the developer tab is displayed. Open the content editor and right click on the ribbon, then from the resulting popup tick the developer option. This will display the developer tab on the content editor.

developer tab

Once you have selected the developer tab you will notice the new Serialize chunk. To serialize an item to disk I just use on of the serialize options to either serialize a single item or the current subtree starting at the currently selected item. Alex de Groot recently did a few posts on these new features and also a good video showing off the new features. I won’t repeat what he said, so go and check out Sitecore 6 serialization part 1 and Sitecore 6 serialization part 2

The files are going to land in the data folder under a new folder called serialization. Once here we can put them into source control quite easily.

An alterative to the above approach, or if you’re on Sitecore 5.3.x, is to use Revolver. We can combine the gi command which gets an items XML, with the echo command to write that data to any file. gi also accepts a parameter -r which will grab the XML for this item and it’s children (subtree). The nice thing (or dangerous depending on how you look at it) is that I can put the file anywhere on disk. Oh, and that’s the other thing. Revolver will output a single file and Sitecore item serialization above will output many little files.

So here’s some Revolver commands to output first a single item, then a subtree:

echo -f c:\temp\item.xml < gi
echo -f c:\temp\tree.xml < (gi -r)

To restore items into the tree I have to use the touch command combined with the echo command. Placing the -i parameter on the echo command now reverses the direction of the file operation. Instead of writing to file, I’m reading from file directly into Revolver.

touch -x < (echo -i -f c:\temp\item.xml)

I need to take a little more care when using Revolver as I can move the items around. The Sitecore item serialization takes care of all that for us.

And again, once the file is on disk we can just pull it into source control very easily. How do you choose which one to use? A lot will come down to preference. The rest will come down to how much control I want over where the items are serialized on disk and how they get deserialized.

If I were to go the Revolver path, I would highly suggest writting some scripts to take care of this and to keep a consistent location on disk.

Categories: Revolver, Sitecore
Follow

Get every new post delivered to your Inbox.