codeflood logo

Automated Testing and Sitecore - Part 4

So far in this series we have covered some of the theories and techniques required to automate testing of Sitecore components, creating a custom NUnit test runner which runs inside the Sitecore website and exposes the Sitecore context to the running tests and how to programmatically setup our test environment for repeatable testing against know content structures. In this post we are going to start testing some code.

The tests we'll cover in this post will be any code written against the Sitecore API. To use the Sitecore API you generally require a Sitecore context. So the tests against this code will be run inside the custom NUnit test runner we created back in part 2 of this series.

The code I am going to test will be a simple content utility method which returns an item's summary. Our item has a "summary" field, but if that is empty the method should return the first 100 characters of the "text" field. If there are more than 100 characters in the text field the method should append an ellipsis (...) to the end of the summary.

Let's approach this in a TDD way. So first I'll write some tests. The first case I'll test will be with an appropriate item that contains both summary and the text fields. I created the test items which these tests use during my TestFixtureSetUp method as detailed in part 3 of this series. Note: the below code is NUnit tests as the custom test runner runs NUnit tests.

[Test]
public void WithSummaryPopulated()
{
  Item testItem = Sitecore.Context.Database.GetItem
    ("/sitecore/content/home/With Summary");
  Assert.AreEqual("The item summary", Util.GetSummary(testItem));
}

Next I'll test with an appropriate item where the summary field is empty.

[Test]
public void WithoutSummaryPopulated()
{
  Item testItem = Sitecore.Context.Database.GetItem
    ("/sitecore/content/home/Without Summary");
  Assert.AreEqual("This is some text without summary", Util.GetSummary(testItem));
}

Now for an item which doesn't contain any of the required fields.

[Test]
public void NoFields()
{
  Item testItem = Sitecore.Context.Database.GetItem
    ("/sitecore/content/home/No Fields");
  Assert.AreEqual(string.Empty, Util.GetSummary(testItem));
}

There's a few basic tests. I would also want to provide tests for items without a summary and less than 100 characters in text, and above 100 characters in text, to test the cases for the ellipsis. You need to provide enough tests to ensure you have tested for known good and bad cases.

With the tests in place I can now start writing my code. If I try to compile now I'll get complication errors due to the util method above not existing. So I'll start by writing the stub for the method. After that if I run my tests they should fail as my method doesn't yet do anything. And now after we've witnessed our tests failing, to prove that they can fail and they are testing against the cases we desire, we can fill in the body of the util method.

public static class Util
{
  public static string GetSummary(Item item)
  {
    if (item["summary"] != string.Empty)
      return item["summary"];
    else if (item["text"].Length > 100)
      return item["text"].Substring(0, 100) + "...";
    else
      return item["text"];
  }
}

From the examples given above, the first thing the detractors of TDD will point out is that we have written more test code than code under test. That may be the case in these examples, but note that a lot of the testing code is repetitive, and I actually copied and pasted much of that. But the clipboard does not make for a maintainable solution. So let's refactor our tests. I'll put out a method which encapsulates the common code.

private void TestItem(string path, string expected)
{
  Item testItem = Sitecore.Context.Database.GetItem(path);
  Assert.AreEqual(expected, Util.GetSummary(testItem));
}

[Test]
public void WithSummaryPopulated()
{
  TestItem("/sitecore/content/home/With Summary", "The item summary");  }

[Test]
public void WithoutSummaryPopulated()
{
  TestItem("/sitecore/content/home/Without Summary", "This is some text without summary");
}

[Test]
public void NoFields()
{
  TestItem("/sitecore/content/home/No Fields", string.Empty);
}

Wow! I saved 3 lines of code! Well, in the above examples I did. But applying this technique to real code I end up saving many more lines. The above example are quite academic and contrived.

This is actually the wrong time to be refactoring. When I started to write the second test and noticed it was quite like the first is when I should have started to refactor and saved the effort of all that copy-pasting and rework of the other test methods.

Using these techniques you can write tests that exercise your code which uses the Sitecore API. The main piece here is that your test is run within the custom NUnit test runner to provide the Sitecore Context. In the next post in this series we'll start testing our controls and presentation components.

Comments

Leave a comment

All fields are required.