I am in the process of setting up some unit tests for a Sitecore project (using this guide as a starting point: https://www.codeflood.net/blog/2020/05/17/logicless-view-itemless-model/)
I have come across a problem when trying to mock returning an ImageField.
This is the method I would like to test:
public string GetImageUrl(Item item, string fieldName, MediaUrlBuilderOptions options = null)
{
if (item == null)
return String.Empty;
if(string.IsNullOrWhiteSpace(fieldName))
return String.Empty;
var imgField = (ImageField)item.Fields[fieldName];
if (imgField != null && imgField.MediaItem != null)
{
return (options != null) ?
HashingUtils.ProtectAssetUrl(_mediaManager.GetMediaUrl(imgField.MediaItem, options)) :
HashingUtils.ProtectAssetUrl(_mediaManager.GetMediaUrl(imgField.MediaItem));
}
return String.Empty;
}
The code I have so far works to some degree, when I make the call for item.Fields[fieldName], it returns the raw value
< image mediaid='{12345678-1234-1234-1234-123456789012}' /> which casts into an ImageField. However, the MediaItem property of this ImageField is always null, thus I cant proceed to mock calling getMediaUrl.
[Fact]
public void GetImageUrl_KnownFieldName_ReturnsValue()
{
// arrange
var item = CreateItem();
SetItemField(item, "Some Known Field", "<image mediaid='{12345678-1234-1234-1234-123456789012}' />");
var mediaManager = Substitute.For<BaseMediaManager>();
var sut = new ImageTaxonomy(mediaManager);
// act
var results = sut.GetImageUrl(item, "Some Known Field");
// assert
Xunit.Assert.Equal("Desired value", results);
}
private Item CreateItem()
{
var database = Substitute.For<Database>();
var mediaItem = Substitute.For<Item>(ID.NewID, ItemData.Empty, database);
database.GetItem(new ID("12345678-1234-1234-1234-123456789012")).Returns(mediaItem);
var item = Substitute.For<Item>(ID.NewID, ItemData.Empty, database);
var fields = Substitute.For<FieldCollection>(item);
item.Fields.Returns(fields);
return item;
}
private void SetItemField(Item item, string fieldName, string fieldValue)
{
var field = Substitute.For<Field>(ID.NewID, item);
field.Value = fieldValue;
field.Database.Returns(item.Database);
item.Fields[fieldName].Returns(field);
}
As you can see I tried mocking the call to database.GetItem(), with the intent of returning the desired mediaItem, but that didnt do the trick.
Any advice on how to proceed would be much appreciated.
EDIT: Updated Solution
This is the updated code with correctly mocked media item.
Note: there is still an issue with my use of BaseMediaManager, but that will be focus of another question. (How to mock MediaManager in Sitecore using nSubstitute and xUnit)
public void GetImageUrl_KnownFieldName_ReturnsValue()
{
// arrange
var database = Substitute.For<Database>();
var item = CreateItem(database);
SetItemField(item, "Some Known Field", $"<image mediaid='{mediaItemIDString}' />");
var mediaItem = CreateMediaItem(database);
database.GetItem(mediaItemID, Arg.Any<Language>(), Sitecore.Data.Version.Latest).Returns(mediaItem);
var mediaManager = Substitute.For<BaseMediaManager>();
mediaManager.GetMediaUrl(mediaItem).Returns("/a/path/to/an/image.jpg");
var sut = new ImageTaxonomy(mediaManager);
// act
var results = sut.GetImageUrl(item, "Some Known Field");
// assert
Xunit.Assert.Equal("/a/path/to/an/image.jpg", results);
}
private Item CreateItem(Database database = null)
{
var item = Substitute.For<Item>(ID.NewID, ItemData.Empty, database);
var fields = Substitute.For<FieldCollection>(item);
item.Fields.Returns(fields);
return item;
}
private Item CreateMediaItem(Database database = null)
{
var definition = new ItemDefinition(mediaItemID, "Mock Media Item", ID.Null, ID.Null);
var data = new ItemData(definition, Language.Current, Sitecore.Data.Version.First, new FieldList());
var mediaItem = new Item(mediaItemID, data, database);
return mediaItem;
}
private void SetItemField(Item item, string fieldName, string fieldValue)
{
var field = Substitute.For<Field>(ID.NewID, item);
field.Value = fieldValue;
field.Database.Returns(item.Database);
item.Fields[fieldName].Returns(field);
}