codeflood logo

Automated Testing and Sitecore - Part 6

In this installment we'll cover testing the static behaviors and presentation of our other Sitecore presentation components; layouts, sublayouts and renderings. These components are more difficult to test as they need to be hosted inside a Sitecore page to allow testing them. Because these components will be hosted in a page, we will be making web requests to the server to get the page output, then perform our assertions on the markup. This is almost as far from a unit test as you can get. But remember the name of this series. We're interested in automated testing, not in unit testing.

Being that we'll be making standard HTTP requests to the server, these tests do not have to be hosted inside the custom test runner, although they can if you wish. In fact, these tests can even be run from a different machine than that running Sitecore. There will still be some testing code required on the Sitecore server though, to handle the creation and cleanup of our test content.

Firstly we'll need to create a test page which will host the Sitecore component under test. When we define presentation for an item, all we're doing is editing the XML data in the "__renderings" field of the item. This is the field which Sitecore uses to work out the presentation for the item.

The easiest way to set presentation for an item programatically to include a presentation component to test is to set the presentation in the content editor, then turn on "raw values" and copy the XML data. We can then set the __renderings field the same as any other field.

Item home = Sitecore.Context.Database.GetItem("/sitecore/content/home");
TemplateItem template = Sitecore.Context.Database.Templates["sample/sample item"];
Item myItem = home.Add("My Item", template);
using (new EditContext(myItem))
{
  myItem["__renderings"] = "<?xml version=\"1.0\" encoding=\"utf-16\"?>
    <r xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}" l="{BC88973F-D93B-47A4-85A0-D51034C457CF}">
    <r ds="" id="{7F2B13A6-8A2C-4A4F-93B2-582A043368CF}" par="" ph="page-columns" uid="{AF72D0AF-A0DC-4669-929D-278698200811}" />
    </d>
    <d id="{46D2F427-4CE5-4E1F-BA10-EF3636F43534}" l="" />
    </r>
}

The above code creates a new page and defines a simple presentation to use a specific layout and bind a single sublayout into the correct placeholder. If we look more closely at the XML of the renderings field we can start to see properties that we manipulate through the UI and would need to be adjusted to affectively perform testing against the component.

Let's format that XML a bit nicer here and have a look at it.

<?xml version="1.0" encoding="utf-16"?>
<r xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}" l="{BC88973F-D93B-47A4-85A0-D51034C457CF}">
    <r ds="" id="{7F2B13A6-8A2C-4A4F-93B2-582A043368CF}" par="" ph="page-columns" uid="{AF72D0AF-A0DC-4669-929D-278698200811}" />
  </d>
  <d id="{46D2F427-4CE5-4E1F-BA10-EF3636F43534}" l="" />
</r>

The "r" element is for rendering, either the whole rendering definition or a single presentation component such as a rendering or sublayout. The "d" element is for a device such as "print" or "default" which are both displayed above. In the device element, we can see the attribute "l" for the ID of the layout. In the rendering element, the "id" attribute indicates the ID of the presentation component, "ds" is the data source, "par" are the parameters and "ph" is the placeholder key to bind into.

If we use the UI in the content editor to set some parameters and a data source we can reveal the format of that data.

<r
  ds="/sitecore/content/Home/News"
  id="{7F2B13A6-8A2C-4A4F-93B2-582A043368CF}"
  par="param1=val1&amp;param2=val2"
  ph="page-columns"
  uid="{AF72D0AF-A0DC-4669-929D-278698200811}" />

So we can see the data source is the full sitecore path to the data source item and the parameters should be provided in a query string style. Once we understand the format here we can manipulate it programmatically to adjust these properties to allow more complete testing.

Now that we know how to set the presentation for an item, we can continue onto creating the test setup page. To create this test page from outside of Sitecore we can use the techniques I spoke about in part 3 of this series. To summarise: create a page inside Sitecore which when hit with the correct query string, will use the above code to create the required items and set their presentation. Now we have a known content structure to test against as well as a page hosting the presentation component we wish to test. We will use standard WebRequests to pull the output of the page back over HTTP, then perform our assertions on the output.

using System.Net;
using System.IO;

namespace Testing
{
  public class PresTest
  {
    [Test]
    public void MyTest()
    {
      const string DOMAIN = "http://localhost";
      WebRequest request = WebRequest.Create(DOMAIN + "/test-page-1.aspx");
      WebResponse response = request.GetResponse();
      StreamReader reader = new StreamReader(response.GetResponseStream());
      string output = reader.ReadToEnd();
    }
  }
}

We can perform our assertions using any of the techniques described in part 5 of this series. These are string comparison, regular expressions and HtmlAgilityPack. The presentation components being tested in these scenarios are usually more complex than a few string literals placed into the output. They will contain structure so I would suggest HtmlAgilityPack would be the easiest to use to test these components.

HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(output);
XPathNavigator nav = doc.CreateNavigator();
XPathNodeIterator div = nav.Select("//div[@class='breadcrumb']");
Assert.AreEqual(1, div.Count);
div.MoveNext();

XPathNodeIterator liLinks = div.Select("ul/li/a");
Assert.AreEqual(5, liLinks.Count);
liLinks.MoveNext();

Of course, if we're using HtmlAgilityPack we don't have to worry about executing the web request ourselves. Instead we can use the HtmlWeb component provided by HtmlAgilityPack to do the loading for us.

HtmlWeb web = new HtmlWeb();
HtmlDocument doc = web.Load(DOMAIN + "/test-page-1.aspx");

Note that we're only testing the static output of the presentation components. We can't interact with the markup or test the javascript. Those topics will be covered in the next part of this series.

Comments

Leave a comment

All fields are required.