Category Archives: Unit testing

Unit testing Sitecore Webforms? It’s possible with the MVP pattern.

As I have described in my previous post about unit testing with Sitecore MVC, unit testing with Sitecore MVC is possible. To make that easy/possible you have to abstract some of the Sitecore classes away into a wrapper. You quickly get used to the fact that the common sitecore classes are abstracted away and you are programming against a wrapper.

One of the perks of MVC as opposed to Webforms development is that is is easy to unit test. This is partially due to the fact that the controls of a Webforms page or control are directly accessed in the code behind. To make a Webforms project more unit testable, you can implement the MVP pattern.

The Model-View-Presenter pattern (or MVP)

I am not stating that is is easy to unit test a Webforms project, but when choosing the right pattern for the job it can be done. The Model-View-Presenter pattern (MVP) is my pattern of choice for this matter. It does a nice job of separating the logic from the presentation. When using the MVP pattern I use the WebformsMVP framework which can be easily installed using Nuget.

Example

I have created a simple example in which I want to have a Usercontrol that contains an image and an image description. If no image is available I want the image to be hidden.

The Model

The model we are using to provide the data to the view looks like this:

public class MediaImageModel
{
    public string Image { get; set; }

    public bool ShowImage
    {
        get { return !string.IsNullOrEmpty(Image); }
    }

    public string ImageDescription { get; set; }
}

The Image property contains the image url.

The Presenter

The presenter manipulates the model and handles the user interaction if necessary which is not the case here.

public class MediaImagePresenter : Presenter<IView<MediaImageModel>>
{
    private readonly ISitecoreContext sitecoreContext;

    public MediaImagePresenter(IView<MediaImageModel> view, ISitecoreContext context)
        : base(view)
    {
        sitecoreContext = context;
        this.View.Load += Load;
    }

    public void Load(object sender, EventArgs e)
    {
        IMediaImageItem model = sitecoreContext.CurrentItem as IMediaImageItem;

        this.View.Model.Image = model.Image.Url;
        this.View.Model.ImageDescription = model.ImageDescription.RenderedValue;
    }
}

The presenter take a view that uses a model of type MediaImageModel. The constructor takes a view which is injected by the WebformsMvp framework. It also takes a context of type ISitecoreContext which is injected using Unity.

this.View.Load

is a method that is fired during the Load event. Since I am still using Synthesis to access the items through generated interface representations of that template, the current item is cast to the IMediaImageItem interface.

The View – codebehind

public partial class MediaImage : MvpUserControl<MediaImageModel>
{}

This control inherits from MvpUserControl which uses a MediaImageModel. Through conventions the WebformsMvp framework links the MediaImagePresenter to the MediaImage control.

The View – markup

<asp:Image runat="server" ID="Image" Visible="<%#Model.ShowImage %>" ImageUrl="<%#Model.Image %>"/>
<asp:Literal runat="server" ID="ImageDescription" Text="<%#Model.ImageDescription %>"/>

The load event in the presenter is fired. After that the public property Model is filled and available in the markup.
All done…except for the unit testing part.

Unit testing

Since we have now separated the logic from the presentation we can determine if the model is filled according to our specifications. to test this I have created three unit tests.

public partial class MediaImage : MvpUserControl<MediaImageModel>
[TestClass()]
public class MediaImagePresenterTests
{
    private Mock<IMediaImageItem> CreateNewMockMediaImageItem(string imageDescription = "", string imageUrl = "")
    {
        var mediaImageItem = new Mock<IMediaImageItem>();

        mediaImageItem.SetupGet(x => x.Image).Returns(new TestImageField(imageUrl));
        mediaImageItem.SetupGet(x => x.ImageDescription).Returns(new TestTextField(imageDescription));
        return mediaImageItem;
    }

    private Mock<IMediaImageView> CreateNewMockMediaImageView()
    {
        return new Mock<IMediaImageView>();
    }

    [TestMethod()]
    public void Load_IMediaImageItemWithEmptyImageUrl_ImageEmptyAndInvisible()
    {
        // Arrange
        Mock<IMediaImageItem> mediaImageItem = CreateNewMockMediaImageItem(imageDescription: "", imageUrl: "");
        Mock<IMediaImageView> view = CreateNewMockMediaImageView();
        view.SetupGet(x => x.Model).Returns(new MediaImageModel());
        SitecoreContext sitecoreContext = new SitecoreContext() { CurrentItem = mediaImageItem.Object };

        // Act
        MediaImagePresenter presenter = new MediaImagePresenter(view.Object, sitecoreContext);
        presenter.Load(null, null);

        // Assert
        Assert.AreEqual("", presenter.View.Model.Image);
        Assert.AreEqual(false, presenter.View.Model.ShowImage);
    }

    [TestMethod()]
    public void Load_IMediaImageItemWithFilledImageUrl_ImageFilledAndVisible()
    {
        // Arrange
        Mock<IMediaImageItem> mediaImageItem = CreateNewMockMediaImageItem(imageDescription: "", imageUrl: "imageurl.jpg");
        Mock<IMediaImageView> view = CreateNewMockMediaImageView();
        view.SetupGet(x => x.Model).Returns(new MediaImageModel());
        SitecoreContext sitecoreContext = new SitecoreContext() { CurrentItem = mediaImageItem.Object };

        // Act
        MediaImagePresenter presenter = new MediaImagePresenter(view.Object, sitecoreContext);
        presenter.Load(null, null);

        // Assert
        Assert.AreEqual("imageurl.jpg", presenter.View.Model.Image);
        Assert.AreEqual(true, presenter.View.Model.ShowImage);
    }

    [TestMethod()]
    public void Load_IMediaImageItemWithImageDescription_ImageDescriptionFilled()
    {
        // Arrange
        Mock<IMediaImageItem> mediaImageItem = CreateNewMockMediaImageItem(imageDescription: "TestImageDescription", imageUrl: "");
        Mock<IMediaImageView> view = CreateNewMockMediaImageView();
        view.SetupGet(x => x.Model).Returns(new MediaImageModel());
        SitecoreContext sitecoreContext = new SitecoreContext() { CurrentItem = mediaImageItem.Object };

        // Act
        MediaImagePresenter presenter = new MediaImagePresenter(view.Object, sitecoreContext);
        presenter.Load(null, null);

        // Assert
        Assert.AreEqual("TestImageDescription", presenter.View.Model.ImageDescription);
    }
}

And there you have it: A unit tested usercontrol that uses the MVP pattern. For simple sites I must say that this approach can make simple things complex. You have to write more code to accomplish the same.
I think that when you want to unit test a Webforms project, you should look into the MVP pattern. When building a new project, I would go with MVC.

Unit testing Sitecore MVC? It’s easy when using Synthesis

I have been using Sitecore for a while now, and one of the nice features of the Sitecore API is that it is flexible in presenting field values.

string title = Sitecore.Context.Item["title"];

No matter what type of template you use, if it has a title field, this line of code will work. In fact, this code works even if the template does not have a title field.

Unit testing sitecore using MVC and Synthesis ORM

For a while I have switched from Webforms to MVC. This makes me more conscious of the templates I use, because I now pass a strongly typed model from the controller to the view. I wanted to try an ORM and decide to go with Kam Figy’s Synthesis. It easy to configure, it autogenerates interfaces and concrete classes and it is easily unit testable.

Synthesis generates interfaces and concrete classes based on the templates you include. It is configurable to in- or exclude templates and fields. It is easily installed using Nuget packages and has a Synthesis.Testing package that contains dummy field type implementations to help you write cleaner mocks of Synthesis item types.

After reading Martina Welander’s post on Unit Testing Sitecore MVC we decided to use this as a starting point and combine this with the Synthesis ORM we are using.

Interfaces

First we created interfaces for the parts of the Sitecore.Context we use regularly.

public interface ISiteContextAdapter
{
  IStandardTemplateItem RootItem { get; }
}

public interface ISitecoreContext
{
  IStandardTemplateItem CurrentItem { get; }
  IStandardTemplateItem HomepageItem { get; }
  bool IsPageEditor { get; }
  bool IsPreview { get; }
  ISiteContextAdapter Site { get; }
  IDatabaseAdapter Database { get; }
  RenderingParameters Parameters { get; }
  IStandardTemplateItem DatasourceItem { get; }
  string Placeholder { get; }
}

Instead of returning an Item we chose to return an IStandardTemplateItem. This is the base interface implemented by all template interfaces generated with Synthesis. Instead of the Sitecore.Context.Database we used the IDatabaseAdapter that comes with Synthesis.

Concrete implementation

We created the SitecoreContext class that implements the ISitecoreContext interface. An object of this type is injected in every controller constructor using Dependency Injection. This is where we hook up the coupling with the Sitecore.Context.

public class SiteContextAdapter : ISiteContextAdapter
{
  private readonly SiteContext siteContext;
  private readonly IDatabaseAdapter databaseAdapter;

  public SiteContextAdapter(SiteContext siteContext, IDatabaseAdapter databaseAdapter)
  {
    this.siteContext = siteContext;
    this.databaseAdapter = databaseAdapter;
  }

  public IStandardTemplateItem RootItem{
    get{
      return this.databaseAdapter.GetItem(this.siteContext.RootPath);
    }
  }
}

public class SitecoreContext : ISitecoreContext
{
  private RenderingContext rendering = RenderingContext.CurrentOrNull;

  public IStandardTemplateItem CurrentItem{
    get{
      return Sitecore.Context.Item.AsStronglyTyped();
    }
  }

  public IDatabaseAdapter Database{
    get{
      return new DatabaseAdapter(Sitecore.Context.Database);
    }
  }

  public IStandardTemplateItem DatasourceItem{
    get{
      if (this.rendering != null && this.rendering.Rendering.Item != null)
      {
        return this.rendering.Rendering.Item.AsStronglyTyped();
      }
      return null;
    }
  }

  public IStandardTemplateItem HomepageItem{
    get{
      return this.Database.GetItem(Sitecore.Context.Site.StartPath);
    }
  }

  public ISiteContextAdapter Site{
    get{
      return new SiteContextAdapter(Sitecore.Context.Site, this.Database);
    }
  }

  public bool IsPageEditor{
    get{
      return Sitecore.Context.PageMode.IsPageEditor;
    }
  }

  public bool IsPreview{
    get{
      return Sitecore.Context.PageMode.IsPreview;
    }
  }

  public RenderingParameters Parameters{
    get{
      return this.rendering.Rendering.Parameters;
    }
  }

  public string Placeholder{
    get{
      if (this.rendering != null && this.rendering.Rendering != null)
      {
        return this.rendering.Rendering.Placeholder;
      }
      return null;
    }
  }
}

Fakes implementation

To be able to unit test we also create fake classes to use in our unit tests.

public class FakeSiteContextAdapter : ISiteContextAdapter
{
  public FakeSiteContextAdapter(IStandardTemplateItem rootItem = null)
  {
    this.RootItem = rootItem;
  }

  public IStandardTemplateItem RootItem { get; set; }
}

public class FakeSitecoreContext : ISitecoreContext
{
  public FakeSitecoreContext(IStandardTemplateItem current = null, IStandardTemplateItem home = null, IStandardTemplateItem datasourceItem = null, bool isPageEditor = false, bool isPreview = false, RenderingParameters parameters = null, IDatabaseAdapter database = null, string placeholder = null, ISiteContextAdapter site = null)
  {
    this.CurrentItem = current;
    this.HomepageItem = home;
    this.IsPageEditor = isPageEditor;
    this.IsPreview = isPreview;
    this.Database = database;
    this.DatasourceItem = datasourceItem;
    this.Parameters = parameters;
    this.Placeholder = placeholder;
    this.Site = site;
  }

  public IStandardTemplateItem CurrentItem { get; set; }
  public IDatabaseAdapter Database { get; set; }
  public IStandardTemplateItem DatasourceItem { get; set; }
  public IStandardTemplateItem HomepageItem { get; set; }
  public bool IsPageEditor { get; set; }
  public bool IsPreview { get; set; }
  public RenderingParameters Parameters { get; set; }
  public string Placeholder { get; set; }
  public ISiteContextAdapter Site { get; set; }
}

Implementation Unit Test

Now we are going to write a unit test using the FakeSitecoreContext. This unit test tests the controller action that provides an actionresult of a view that takes a model containing a MetaTitle. We are passing in a mocked item of the MetaInformation template.

[TestMethod]
public void HeaderMetaTitleProvidedTest()
{
  string metaTitle = "My meta title";

  // create a mock item
  var metaInformationItem = new Mock<IMetaInformationItem>();
  metaInformationItem.SetupGet(x => x.MetaTitle).Returns(new TestTextField(metaTitle));

  // setup the fake context
  FakeSitecoreContext sitecoreContext = new FakeSitecoreContext() { CurrentItem = metaInformationItem };

  TagsController controller = new TagsController(sitecoreContext);
  var result = controller.MetaTags() as ViewResult;
  IMetaInformationItem model = result.Model as IMetaInformationItem;

  Assert.IsNotNull(controller);
  Assert.IsNotNull(model);
  Assert.IsTrue(model.MetaTitle.RawValue.Equals(metaTitle));
}

Controller implementation

Al we have to do now is make our unit test pass by actually writing the controller. In the controller we use an object that implements the ISitecoreContext interface. So no tight coupling with the Sitecore.Context. An object of type SitecoreContext is injected using Dependency Injection. Also we use a model that implements the IMetaInformationItem interface generated by Synthesis. This interface is based on the MetaInformation template. This helps us in the view since we have a strongly typed object with all its properties.

public class TagsController : Controller
{
  private ISitecoreContext sitecoreContext;

  public TagsController(ISitecoreContext sitecoreContext)
  {
    this.sitecoreContext = sitecoreContext;
  }

  public ViewResult MetaTags()
  {
    IMetaInformationItem model = sitecoreContext.CurrentItem as IMetaInformationItem;
    return View(model);
  }
}

Result

With the wrapping of the Sitecore.Context and the Dependency Injection in place we can now unit test the results our controller actions give us. We can use the TestFields provided with Synthesis to easily mock our items. We can now develop faster, correct code. Unit testing sitecore  can improve the quality of your code. I wouldn’t have it any other way.