Last active
January 26, 2024 19:33
-
-
Save nickwesselman/04c6f35beb6aac2a540fb69c118d2304 to your computer and use it in GitHub Desktop.
Unit Testing Sitecore ContentSearch (LINQ to Sitecore) using Moq
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Linq; | |
using Sitecore.Abstractions; | |
using Sitecore.ContentSearch; | |
using Sitecore.Data.Items; | |
namespace BasicCompany.Feature.Products.Services | |
{ | |
public class ProductRepository : IProductRepository | |
{ | |
protected readonly BaseFactory Factory; | |
protected readonly BaseItemManager ItemManager; | |
public ProductRepository(BaseFactory factory, BaseItemManager itemManager) | |
{ | |
Debug.Assert(factory != null); | |
Debug.Assert(itemManager != null); | |
Factory = factory; | |
ItemManager = itemManager; | |
} | |
public IEnumerable<Item> GetProducts(Item parent) | |
{ | |
using (var context = GetSearchContext(parent)) | |
{ | |
var results = context.GetQueryable<ProductSearchQuery>() | |
.Where(product => product.Paths.Contains(parent.ID) && product.Templates.Contains(Templates.Product.Id)) | |
.Select(x => new { | |
Uri = x.UniqueId, | |
Database = Factory.GetDatabase(x.UniqueId.DatabaseName) | |
}).ToList(); | |
return results.Select(x => ItemManager.GetItem(x.Uri.ItemID, x.Uri.Language, x.Uri.Version, x.Database)); | |
} | |
} | |
protected virtual IProviderSearchContext GetSearchContext(Item item) | |
{ | |
return ContentSearchManager.GetIndex((SitecoreIndexableItem)item).CreateSearchContext(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Linq; | |
using BasicCompany.Feature.Products.Services; | |
using Moq; | |
using Moq.Protected; | |
using Sitecore.Abstractions; | |
using Sitecore.ContentSearch; | |
using Sitecore.Data; | |
using Sitecore.Data.Items; | |
using Sitecore.Globalization; | |
using Xunit; | |
using Version = Sitecore.Data.Version; | |
namespace BasicCompany.Feature.Products.Tests | |
{ | |
public class ProductRepositoryTests | |
{ | |
[Fact] | |
public void FiltersOnPathAndTemplate() | |
{ | |
// Mock the database | |
var db = Mock.Of<Database>(); | |
// Mock the parent item | |
var parentId = ID.NewID; | |
var parentDef = new ItemDefinition(parentId, "parent", Templates.Product.Id, ID.Null); | |
var parentData = new ItemData(parentDef, Language.Parse("en"), Version.Parse(1), new FieldList()); | |
var parent = new Mock<Item>(parentId, parentData, db); | |
// Mock the Sitecore services | |
var factoryMock = new Mock<BaseFactory>(); | |
factoryMock.Setup(x => x.GetDatabase(It.IsAny<string>())).Returns(db); | |
var factory = factoryMock.Object; | |
var itemManager = Mock.Of<BaseItemManager>(); | |
// Mock search context, so we are testing LINQ to Objects instead of LINQ to Sitecore | |
var itemUri = new ItemUri("sitecore://master/{11111111-1111-1111-1111-111111111111}?lang=en&ver=1"); | |
var mockSearchContext = new Mock<IProviderSearchContext>(); | |
mockSearchContext.Setup(x => x.GetQueryable<ProductSearchQuery>()) | |
.Returns(new[] | |
{ | |
// Matches Path and Template | |
new ProductSearchQuery | |
{ | |
UniqueId = itemUri, | |
Templates = new[] {Templates.Product.Id }, | |
Paths = new[] { parentId } | |
}, | |
// Matches Path and Template | |
new ProductSearchQuery | |
{ | |
UniqueId = itemUri, | |
Templates = new[] { ID.NewID, Templates.Product.Id, ID.NewID }, | |
Paths = new[] { ID.NewID, parentId, ID.NewID } | |
}, | |
// Matches Template Only | |
new ProductSearchQuery | |
{ | |
UniqueId = itemUri, | |
Templates = new[] { Templates.Product.Id }, | |
Paths = new[] { ID.NewID } | |
}, | |
// Matches Path Only | |
new ProductSearchQuery | |
{ | |
UniqueId = itemUri, | |
Templates = new[] { ID.NewID }, | |
Paths = new[] { parentId } | |
} | |
}.AsQueryable()); | |
// Use Moq.Protected to ensure our test object uses the mock search context | |
var mockRepo = new Mock<ProductRepository>(factory, itemManager); | |
mockRepo.Protected() | |
.Setup<IProviderSearchContext>("GetSearchContext", ItExpr.IsAny<Item>()) | |
.Returns(mockSearchContext.Object); | |
// Act | |
var result = mockRepo.Object.GetProducts(parent.Object).ToList(); | |
// If the tested class is filtering appropriately, we should get predictible results | |
Assert.Equal(2, result.Count); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using Sitecore.ContentSearch; | |
using Sitecore.Data; | |
namespace BasicCompany.Feature.Products.Services | |
{ | |
public class ProductSearchQuery | |
{ | |
[IndexField("_uniqueid")] | |
public virtual ItemUri UniqueId { get; set; } | |
[IndexField("_path")] | |
public virtual IEnumerable<ID> Paths { get; set; } | |
[IndexField("_templates")] | |
public virtual IEnumerable<ID> Templates { get; set; } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment