3

I have some code that retrieves a glass item like this:

var root = this.RequestContext.SitecoreService.GetItem<ILookupFolderTemplate>(
                new GetItemByIdOptions(new Guid("{DB4B5F35-E3BA-416A-842D-3D25B9C10A23}"))); 

So, using IRequestContext I call the instance of SitecoreService, I request an item using GetItemByIdOptions. This is giving me a problem when I try to mock it for a unit test.

So, for my test (using NSubstitute) I mock the whole process like this:

[Fact]
public void GetItem_RequestContextGetItemOptions_ReturnsCorrectItem()
{
    var idGuid = Guid.NewGuid();

    var product = Substitute.For<ISitecoreItem>();
    product.Name = "Hello world";
    product.ID = new ID(idGuid);

    var context = Substitute.For<IRequestContext>();
    var service = Substitute.For<ISitecoreService>();
    context.SitecoreService.Returns(service);

    context.SitecoreService.GetItem<ISitecoreItem>(new GetItemByIdOptions(idGuid)).Returns(product);

    var result = context.SitecoreService.GetItem<ISitecoreItem>(new GetItemByIdOptions(idGuid));

    result.Should().NotBeNull();
    result.Name.Should().Be("Hello world");
    result.ID.ToGuid().Should().Be(idGuid);
}

And this test fails because result.Name is empty.

BUT, if I create the GetItemByIdOptions separately, like this, it passes:

[Fact]
public void GetItem_RequestContextGetItemOptions_ReturnsCorrectItem()
{
    var idGuid = Guid.NewGuid();

    var product = Substitute.For<ISitecoreItem>();
    product.Name = "Hello world";
    product.ID = new ID(idGuid);

    var context = Substitute.For<IRequestContext>();
    var service = Substitute.For<ISitecoreService>();
    context.SitecoreService.Returns(service);

    var options = new GetItemByIdOptions(idGuid);
    context.SitecoreService.GetItem<ISitecoreItem>(options).Returns(product);

    var result = context.SitecoreService.GetItem<ISitecoreItem>(options);
    result.Should().NotBeNull();
    result.Name.Should().Be("Hello world");
    result.ID.ToGuid().Should().Be(idGuid);
}

Which is all well and good in the context of this test. But when I go and test actual code, I'm not pulling that options out of the GetItem method, I'm instantiating it inside the GetItem statement, so my test fails. It seems like new-ing the options up is the problem. How can I mock this sort of method?

1 Answer 1

2

From what I can see, the reason why it fails for you is because you're using different instances of GetItemByIdOptions class.

First you "record" that when service.GetItem will be called with new GetItemByIdOptions(idGuid), it should return your product.

And then you call service.GetItem with some other new GetItemByIdOptions(idGuid).

Yes, both options the same ID of the item, but it's not the same instance, that's why it doesn't return "recorded" value.

What you can try to do in your test is using ReturnsForAnyArgs instead of Returns while recording desired result of your method:

    context.SitecoreService.GetItem<ISitecoreItem>(new GetItemByIdOptions(idGuid)).ReturnsForAnyArgs(product);

This will make sure that whatever parameter is passed, your product will be always returned.

More info in https://nsubstitute.github.io/help/return-for-any-args/

Or just go with your code when you instantiate options first. In the end, you're not testing if you can create the options instance - you test other bits of logic.

1
  • Excellent. I also found that in the options parameter I can use Arg.Any<GetItemByIdOptions>(), as in context.SitecoreService.GetItem<ISitecoreItem>(Arg.Any<GetItemByIdOptions>()).Returns(product); Both methods work. Not sure of the implications of one over the other yet. Commented Mar 5, 2021 at 12:52

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.