Create simple Unit Tests for the Sitecore Content Search

I recently wanted to test a class where I used the Sitecore Content Search. As I didn’t found a simple example on Google I started to write this blog post. I want to show you in a very simple example how you can create a Unit Test for testing your Content Search queries.

Let’s assume that I have a products data template, with a checkbox field Free (to mark that this is for free) and an Item Bucket where I store all the products. I want to retrieve all products in the Bucket which are for free, using the Sitecore Content Search. So first of all I need a custom model for my search results:

public class ProductSearchResultItem : SearchResultItem
{
    [IndexField("free")]
    public virtual bool Free { get; set; }
}

This model is used in my search repository class. The class is very simple. First I get the search context from Sitecore and get the Queryable (which contains actually all items in the index). Then I filter by my Free field and return the list. The class could look like this:

public class SearchRepository
{
    public virtual IEnumerable<ProductSearchResultItem> GetProducts(SitecoreIndexableItem item)
    {
        using (var context = ContentSearchManager.CreateSearchContext(item))
        {
            var query = context.GetQueryable<ProductSearchResultItem>();

            var products = query.Where(searchResultItem => searchResultItem.Free);

            return products.ToList();
        }
    }
}

And could be used as follow (i.e. in a MVC controller):

var bucketItem = Sitecore.Context.Database.GetItem("<bucket id>")
var repository = new SearchRepository();
var products = repository.GetProducts(bucketItem);

This works fine, but is not testable, because we have a strong dependency to the Sitecore ContentSearchManager. To remove this, we simply need to create a custom method to get the search context. The refactored repository looks like this:

public class SearchRepository
{
    public virtual IEnumerable<ProductSearchResultItem> GetProducts(SitecoreIndexableItem item)
    {
        using (var context = this.GetSearchContext(item))
        {
            var query = context.GetQueryable<ProductSearchResultItem>();

            var products = query.Where(searchResultItem => searchResultItem.Free);

            return products.ToList();
        }
    }

    protected virtual IProviderSearchContext GetSearchContext(SitecoreIndexableItem item)
    {
        return ContentSearchManager.CreateSearchContext(item);
    }
}

This is now the point where we can go to the Unit Test. We want to fake the Lucene index with dummy data, so we need to mock the search context. Fortunately Sitecore has already created an interface IProviderSearchContext, so we can do this easily i.e. with Moq (grab it on NuGet). We will create a fake IProviderSearchContext which returns a dummy index with the GetQueryable() method. Take a look here:

public class TestableSearchRepository : SearchRepository
{
    protected override IProviderSearchContext GetSearchContext(SitecoreIndexableItem item)
    {
        // create the magic product index
        var index = new List<ProductSearchResultItem>();

        index.Add(new ProductSearchResultItem { Free = true });
        index.Add(new ProductSearchResultItem { Free = false });
        index.Add(new ProductSearchResultItem { Free = true });

        // create the mock context
        var context = new Mock<IProviderSearchContext>();
        context.Setup(c => c.GetQueryable<ProductSearchResultItem>()).Returns(index.AsQueryable());
        return context.Object;
    }
}

The fake index contains 3 products where 2 of them are for free. With this new TestableSearchRepository we have no dependency to the Lucene index and can write a very simple unit test:

[Test]
public void GetProductsTest()
{
    // arrange
    var repository = new TestableSearchRepository();

    // act
    var products = repository.GetProducts(null);

    // assert
    Assert.AreEqual(2, products.Count());
}

The item passed to the GetProducts() method can be null, as it’s only used for retrieving the correct search context in the ContentSearchManager. This example should be a starting point for your Unit Tests. If you have a very complex Content Search query, you can now test all your conditions with ease.

Kevin Brechbühl

Senior Developer & Architect | C# & ASP.NET | Sitecore Technology MVP

comments powered by Disqus