3

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);
}

1 Answer 1

3

If you go into ImageField.MediaItem getter, you'll notice that the MediaDatabase.GetItem() method uses 3 parameters including language and version:

this.mediaItem = this.MediaDatabase.GetItem(mediaId, this.MediaLanguage, this.MediaVersion);

In your test you mock another overload of the GetItem() method that uses ID only:

database.GetItem(new ID("12345678-1234-1234-1234-123456789012")).Returns(mediaItem);

So, in order to pass this particular line, you have to update the GetItem call with smth like this (I assume it does not really matter in this scenario which language/version is used so we can use any):

database.GetItem(new ID("12345678-1234-1234-1234-123456789012"),
    Arg.Any<Language>(), Version.Latest).Returns(mediaItem);
1
  • Thanks Serhii, that change has indeed allowed me to progress. I will update my question to show the adjusted code. Marking as accepted answer now. I have now discovered two further issues: [1] The static call to HashingUtils.ProtectAssetUrl() is throwing an exception => how would you normally deal with such calls? Would I move that into view or view model? [2] my mocking of BaseMediaManager doesnt return any data => I will raise a follow up question for this Commented Jan 12, 2022 at 11:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.