/ Umbraco

Mocking Examine, an Umbraco index story

I have been slaving away for the past three weeks trying to mock Examine, the library that Umbraco uses for indexing. It is based on Lucene and seems to be very easy to use. However in my quest to build an example application the TDD way, I needed to mock it. I wanted to build up the search queries up in a “Red Green Refactor” manner.

Once I finished flailing around with Intellisense and Google searches, I cracked open the source code for Examine, and was excited to see unit tests. After reading through the tests and code, I created some factory code to mock the index for use in the Gravyframe tests and I wanted to share them.

using NUnit.Framework;
using Gravyframe.Kernel.Umbraco.Tests.Examine;
using NSubstitute;
namespace Gravyframe.Data.Umbraco.Tests
{
    [TestFixture]
    public class ExampleExamineTests
    {
        private MockedIndex mockedIndex;

        private const string IndexType = "News";
        private const string IndexFeildName = "categoryId";


        [SetUp]
        public void SetUp()
        {
            this.mockedIndex = MockIndexFactory.GetMock(
                new MockIndexFieldList().AddIndexField("id", "Number", true),
                new MockIndexFieldList().AddIndexField(IndexFeildName),
                new[] { IndexType },
                new string[] { },
                new string[] { });

            var mockDataSet = new MockSimpleDataSet(IndexType)
                .AddData(1, IndexFeildName, "category1")
                .AddData(2, IndexFeildName, "category1")
                .AddData(3, IndexFeildName, "category2");

            mockedIndex.SimpleDataService.GetAllData("News").Returns(mockDataSet);

            mockedIndex.Indexer.RebuildIndex();

        }

        [Test]
        public void GetNewByCategory()
        {
            // Act
            var searchCriteria = mockedIndex.Searcher.CreateSearchCriteria();
            var query = searchCriteria.Field("categoryId", "category1").Compile();
            var result = mockedIndex.Searcher.Search(query);

            // Assert
            Assert.IsTrue(result.TotalItemCount == 2);
        }

        [Test]
        public void GetNewByDifferentCategory()
        {
            // Act
            var searchCriteria = mockedIndex.Searcher.CreateSearchCriteria();
            var query = searchCriteria.Field("categoryId", "category2").Compile();
            var result = mockedIndex.Searcher.Search(query);

            // Assert
            Assert.IsTrue(result.TotalItemCount == 1);
        }
    }
}
using Examine;
using Examine.LuceneEngine;
using Examine.LuceneEngine.Providers;
using Lucene.Net.Analysis.Standard;
using NSubstitute;
using Lucene.Net.Store;
using UmbracoExamine;
using System.Collections.Generic;
using System.Linq;

namespace Gravyframe.Kernel.Umbraco.Tests.Examine
{
    public class MockIndexFactory
    {
        public static MockedIndex GetMock(
            MockIndexFieldList standardFields,
            MockIndexFieldList userFields,
            IEnumerable<string> indexTypes,
            IEnumerable<string> includeNodeTypes,
            IEnumerable<string> excludeNodeTypes)
        {
            var index = new MockedIndex
                                  {
                                      StandardFields = standardFields,
                                      UserFields = userFields,
                                      IncludeNodeTypes = includeNodeTypes.ToArray(),
                                      ExcludeNodeTypes = excludeNodeTypes.ToArray(),
                                      SimpleDataService = Substitute.For<ISimpleDataService>(),
                                      LuceneDir = new RAMDirectory()
                                  };

            index.IndexCriteria = new IndexCriteria(standardFields, userFields, index.IncludeNodeTypes, index.ExcludeNodeTypes, -1);

            index.Analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29);

            index.Indexer = new SimpleDataIndexer(index.IndexCriteria, index.LuceneDir, index.Analyzer, index.SimpleDataService, indexTypes, false);

            index.Searcher = new UmbracoExamineSearcher(index.LuceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29));

            return index;
        }
    }
}
using System.Collections.Generic;
using Examine;
using NSubstitute;

namespace Gravyframe.Kernel.Umbraco.Tests.Examine
{
    public class MockIndexFieldList : IEnumerable<IIndexField>
    {
        private List<IIndexField> IndexFieldList { get; set; }

        public MockIndexFieldList()
        {
            IndexFieldList = new List<IIndexField>();
        }

        public MockIndexFieldList AddIndexField(string name, bool enableSorting)
        {
            return AddIndexField(name, string.Empty, enableSorting);
        }

        public MockIndexFieldList AddIndexField(string name)
        {
            return AddIndexField(name, string.Empty);
        }

        public MockIndexFieldList AddIndexField(string name, string type, bool enableSorting = false)
        {
            var indexField = Substitute.For<IIndexField>();
            indexField.Name.Returns(name);
            indexField.EnableSorting.Returns(enableSorting);
            indexField.Type.Returns(type);

            IndexFieldList.Add(indexField);

            return this;
        }

        public IEnumerator<IIndexField> GetEnumerator()
        {
            return IndexFieldList.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return IndexFieldList.GetEnumerator();
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using Examine;
using Examine.LuceneEngine;

namespace Gravyframe.Kernel.Umbraco.Tests.Examine
{
    public class MockSimpleDataSet : IEnumerable<SimpleDataSet>
    {
        private List<SimpleDataSet> ListOfSimpleData { get; set; }
        private string Type { get; set; }

        public MockSimpleDataSet(string type)
        {
            ListOfSimpleData = new List<SimpleDataSet>();
            Type = type;
        }

        public MockSimpleDataSet AddData(int id, string name, string value)
        {
            var nodeDefinition = new IndexedNode {NodeId = id, Type = Type};

            var rowData = new Dictionary<string, string>
            {
                {name, value}
            };

            ListOfSimpleData.Add(
                new SimpleDataSet
                {
                    NodeDefinition = nodeDefinition,
                    RowData = rowData
                });
            return this;
        }


        public IEnumerator<SimpleDataSet> GetEnumerator()
        {
            return ListOfSimpleData.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ListOfSimpleData.GetEnumerator();
        }
    }
}
using Examine;
using Examine.LuceneEngine;
using Lucene.Net.Store;
using System.Collections.Generic;
using Lucene.Net.Analysis;

namespace Gravyframe.Kernel.Umbraco.Tests.Examine
{
    public class MockedIndex
    {
        public ISearcher Searcher { get; set; }

        public IIndexer Indexer { get; set; }

        public ISimpleDataService SimpleDataService { get; set; }

        public Directory LuceneDir { get; set; }

        public MockIndexFieldList StandardFields { get; set; }

        public IIndexCriteria IndexCriteria { get; set; }

        public Analyzer Analyzer { get; set; }
        
        public MockIndexFieldList UserFields { get; set; }

        public IEnumerable<string> IndexTypes { get; set; }

        public IEnumerable<string> IncludeNodeTypes { get; set; }

        public IEnumerable<string> ExcludeNodeTypes { get; set; }

    }
}