1

I am newer to Sitecore and extremely new to its unit testing. been following examples online that mimic exactly what I am trying to accomplish but I seem to be getting an object reference(you will see the error in the screenshots) not set to an instance for an item that I am passing through a function on the unit test and in the function. We had other contracted Sitecore developers on the project in the past write unit tests the same way I am here but their unit tests are passing while throwing that object reference error from their tests. I am working on a Sitecore 10.1 project solution, not that it matter in this situation i think. I am attaching screenshots for clarity on the errors and stack traces. Is this normal for how the unit tests are supposed to be working with Nsubstitute and Sitecore, maybe I am missing the point with how Sitecore works with Unit tests. Please let me know your thoughts :)

enter image description here

        private Item CreateItem(Database database = null)
    {
        var db = database ?? Substitute.For<Database>();

        var item = Substitute.For<Item>(ID.NewID, ItemData.Empty, db);
        var fields = Substitute.For<FieldCollection>(item);
        item.Fields.Returns(fields);

        db.GetItem(item.ID).Returns(item);
        db.GetItem(item.ID.ToString()).Returns(item);

        return item;
    }

    private void SetItemField(Item item, string fieldName, string fieldValue)
    {
        item[fieldName].Returns(fieldValue);

        var field = Substitute.For<Field>(ID.NewID, item);
        field.Database.Returns(item.Database);
        field.Value = fieldValue;
        item.Fields[fieldName].Returns(field);
    }

enter image description here

It seems to be something wrong with how I am setting up the unit tests itself but I have included the whole run through for clarity. If you have any other suggestions for unit testing with Sitecore, I am very open to learning new things with Sitecore :)

2

1 Answer 1

1

You're moving in the right direction. You should keep in mind that you can call only mocked methods. The SetItemField method is configured to return field by name:

item.Fields[fieldName].Returns(field);

... while the GetRelatedContent method tries to retrieve the field via ID:

MultilistField selectedItems = new MultilistField(
    documentItem.Fields[Templates.Document.Fields.RelatedDocuments]);

In order to get the field, the following code should be used:

var multilistField = new MultilistField(documentItem.Fields["RelatedDocument"]);
Assert.Equal(2, multilistField.Count); //pass

In order to get fields by name or id, the SetItemField method can be extended with (for instance) optional fieldId parameter:

private void SetItemField(Item item, string fieldName, string fieldValue, ID fieldId = null)
{
    fieldId = fieldId ?? ID.NewID; // new line

    item[fieldName].Returns(fieldValue);
    item[fieldId].Returns(fieldValue);  // new line

    var field = Substitute.For<Field>(fieldId, item);
    field.Database.Returns(item.Database);
    field.Value = fieldValue;
    item.Fields[fieldName].Returns(field);
    item.Fields[fieldId].Returns(field); // new line
}

Now the field can be retrieved via ID as well:

var RelatedDocumentFieldId = ID.NewID;
SetItemField(documentItem, "RelatedDocument", $"{item1.ID}|{item2.ID}", RelatedDocumentFieldId);
var multilistField = new MultilistField(
    documentItem.Fields[RelatedDocumentFieldId]);
Assert.Equal(2, multilistField.Count); // pass
2
  • 1
    Wow this was an awesome answer and made a lot of sense. That got my unit test working and this makes more sense the way you are explaining it. Thank you for taking the time to answer this question thoroughly!
    – pet3r15
    Commented Feb 17, 2023 at 20:30
  • Added few samples how to mock fields with AutoFixture. Commented Feb 17, 2023 at 20:47

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.