codeflood logo

Automated Testing and Sitecore - Part 3

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.

Comments

Leave a comment

All fields are required.