0

I'm attempting to create a test which verifies that a specific method is called. The method accepts two parameters, and I'd like to check that it gets called with that object having a specific property set.

Here's the code:

private void InitialiseContentTypes()
{
    IContentType blogContentTypeComposition = _blogContentTypeFactory.GetComposition();

    _umbracoContentTypeService.Save(blogContentTypeComposition);
}

This gets the composition from a factory, then uses it in the Save method. In the test, the blogContentTypeComposition should have a property called alias set to aldusBlogComposition (blogContentTypeComposition.Alias).

Here's the test code:

[Test]
[TestCase("aldusBlogComposition")]
public void Initialise_WhenCalled_SavesComposition(string alias)
{
    Mock<IContentType> contentType = new Mock<IContentType>();

    _blogContentTypeFactory
        .Setup(f => f.GetComposition())
        .Callback(() => { contentType.SetupProperty(ct => ct.Alias, alias); });

    _component.Initialize();

    _contentTypeService.Verify(s => s.Save(It.Is<IContentType>(ct => ct.Alias == alias), It.IsAny<int>()), Times.Once);
}

This code creates a mock IContentType and when GetComposition is called, it sets the alias to aldusBlogComposition. Then the Verify should check that the Save method runs once, with the first parameter an IContentType with the alias property set to aldusBlogComposition.

When I run the test, this throws an error (below) which I suspect means that the mock isn't being used in the Verify method call.

Object reference not set to an instance of an object.

What am I missing?

EDIT:

The error is being thrown as part of the contentTypeService.Verify(s => s.Save(It.Is<IContentType>(ct => ct.Alias == alias), It.IsAny<int>()), Times.Once); call. The only thing I can see being null is ct - if I swap this out for just It.IsAny<IContentType>() the error isn't thrown. I understand what a null reference is, but I don't understand why the parameter is null.

Full classes for reference:

Tests class:

using Moq;
using NUnit.Framework;
using Papermoon.Umbraco.Aldus.Core.Components;
using Papermoon.Umbraco.Aldus.Core.Factories.ContentTypes.Interfaces;
using Papermoon.Umbraco.Aldus.Core.Services.Interfaces;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Services;

namespace Papermoon.Umbraco.Aldus.Core.Tests.Components
{
    [TestFixture]
    public class ContentTypeComponentTests
    {
        private Mock<IContentTypeService> _contentTypeService;

        private Mock<IAldusContentTypeContainerService> _contentTypeContainerService;

        private Mock<IBlogContentTypeFactory> _blogContentTypeFactory;

        private ContentTypeComponent _component;

        [SetUp]
        public void SetUp()
        {
            _contentTypeService = new Mock<IContentTypeService>();

            _contentTypeContainerService = new Mock<IAldusContentTypeContainerService>();

            _blogContentTypeFactory = new Mock<IBlogContentTypeFactory>();

            _component = new ContentTypeComponent(_contentTypeService.Object, _contentTypeContainerService.Object, _blogContentTypeFactory.Object);
        }

        [Test]
        public void Initialize_WhenCalled_GetAldusContainer()
        {
            _component.Initialize();

            _contentTypeContainerService.Verify(s => s.GetContainer("Aldus", 1, -1));
        }

        [Test]
        public void Initialise_AldusContainerExists_GetAldusCompositionContainer()
        {
            _contentTypeContainerService
                .Setup(s => s.GetContainer("Aldus", 1, -1))
                .Returns(new EntityContainer(Constants.ObjectTypes.DocumentType)
                {
                    Id = 1
                });

            _component.Initialize();

            _contentTypeContainerService.Verify(s => s.GetContainer("Aldus Compositions", 2, 1));
        }

        [Test]
        public void Initialise_AldusContainerDoesNotExist_DoNoGetAldusCompositionsContainer()
        {
            _contentTypeContainerService
                .Setup(s => s.GetContainer("Aldus", 1, -1))
                .Returns((EntityContainer) null);

            _component.Initialize();

            _contentTypeContainerService.Verify(s => s.GetContainer("Aldus Compositions", 2, It.IsAny<int>()), Times.Never());
        }

        [Test]
        [TestCase("aldusBlogComposition")]
        public void Initialise_WhenCalled_SavesComposition(string alias)
        {
            Mock<IContentType> contentType = new Mock<IContentType>();

            _blogContentTypeFactory
                .Setup(f => f.GetComposition())
                .Callback(() => { contentType.SetupProperty(ct => ct.Alias, alias); });

            _component.Initialize();

            _contentTypeService.Verify(s => s.Save(It.IsAny<IContentType>(), It.IsAny<int>()), Times.Once);
        }

        [Test]
        public void Initialise_WhenCalled_SavesBlogContentType()
        {
            Mock<IContentType> contentType = new Mock<IContentType>();

            contentType.SetupProperty(ct => ct.Alias, "aldus");

            _blogContentTypeFactory
                .Setup(f => f.GetContentType())
                .Returns(contentType.Object);

            _component.Initialize();

            _contentTypeService.Verify(s => s.Save(contentType.Object, It.IsAny<int>()), Times.Once);
        }
    }
}

Component class:

using Papermoon.Umbraco.Aldus.Core.Factories.ContentTypes.Interfaces;
using Papermoon.Umbraco.Aldus.Core.Services.Interfaces;
using Umbraco.Core.Composing;
using Umbraco.Core.Models;
using Umbraco.Core.Services;

namespace Papermoon.Umbraco.Aldus.Core.Components
{
    public class ContentTypeComponent : IComponent
    {
        private readonly IAldusContentTypeContainerService _contentTypeContainerService;

        private readonly IContentTypeService _umbracoContentTypeService;

        private EntityContainer _aldusContainer;

        private readonly IBlogContentTypeFactory _blogContentTypeFactory;

        public ContentTypeComponent(
            IContentTypeService umbracoContentTypeService,
            IAldusContentTypeContainerService contentTypeContainerService,
            IBlogContentTypeFactory blogContentTypeFactory)
        {
            _umbracoContentTypeService = umbracoContentTypeService;

            _contentTypeContainerService = contentTypeContainerService;

            _blogContentTypeFactory = blogContentTypeFactory;
        }

        public void Initialize()
        {
            InitialiseContainers();
            InitialiseContentTypes();
        }

        private void InitialiseContainers()
        {
            _aldusContainer = _contentTypeContainerService.GetContainer("Aldus", 1);

            if (_aldusContainer != null)
            {
                _contentTypeContainerService.GetContainer("Aldus Compositions", 2, _aldusContainer.Id);
            }
        }

        private void InitialiseContentTypes()
        {
            IContentType blogContentTypeComposition = _blogContentTypeFactory.GetComposition();

            _umbracoContentTypeService.Save(blogContentTypeComposition);

            IContentType blogContentType = _blogContentTypeFactory.GetContentType();

            _umbracoContentTypeService.Save(blogContentType);
        }

        public void Terminate() { }
    }
}

And the blog factory class:

using System.Collections.Generic;
using System.Linq;
using Papermoon.Umbraco.Aldus.Core.Factories.ContentTypes.Interfaces;
using Papermoon.Umbraco.Utils.Services.Interfaces;
using Umbraco.Core.Models;
using Umbraco.Core.Services;

namespace Papermoon.Umbraco.Aldus.Core.Factories.ContentTypes
{
    public class BlogContentTypeFactory : ContentTypeFactory, IBlogContentTypeFactory
    {
        public BlogContentTypeFactory(
            IContentTypeService contentTypeService,
            IPapermoonContentTypeService papermoonContentTypeService,
            IPapermoonContentTypeContainerService papermoonContentTypeContainerService,
            IPapermoonTemplateService papermoonTemplateService)
            : base(
                contentTypeService,
                papermoonContentTypeService,
                papermoonContentTypeContainerService,
                papermoonTemplateService) { }

        public IContentType GetComposition()
        {
            Composition = ContentTypeService.Get("aldusBlogComposition");

            if (Composition == null)
            {
                Composition = new ContentType(AldusCompositionsContainer.Id);
            }

            Composition.Name = "Aldus Blog Composition";
            Composition.Alias = "aldusBlogComposition";
            Composition.Description = "A composition for the Aldus blog listing.";
            Composition.Icon = "icon-settings";

            return Composition;
        }

        public IContentType GetContentType()
        {
            ContentType = ContentTypeService.Get("aldusBlog");

            if (ContentType == null)
            {
                ContentType = new ContentType(AldusContainer.Id);
            }

            ContentType.Name = "Blog";
            ContentType.Alias = "aldusBlog";
            ContentType.Description = "Aldus blog listing.";
            ContentType.Icon = "icon-article";

            ContentType.AllowedTemplates = PapermoonTemplateService.Get(new [] { "AldusBlog" });

            ContentType.SetDefaultTemplate(ContentType.AllowedTemplates.First());

            ContentType.ContentTypeComposition =
                PapermoonContentTypeService.GetCompositions(ContentType, new List<string> {"aldusBlogComposition"});

            return ContentType;
        }
    }
}

And finally, the content type factory class:

using System.Collections.Generic;
using System.Linq;
using Papermoon.Umbraco.Aldus.Core.Factories.ContentTypes.Interfaces;
using Papermoon.Umbraco.Utils.Services.Interfaces;
using Umbraco.Core.Models;
using Umbraco.Core.Services;

namespace Papermoon.Umbraco.Aldus.Core.Factories.ContentTypes
{
    public class BlogContentTypeFactory : ContentTypeFactory, IBlogContentTypeFactory
    {
        public BlogContentTypeFactory(
            IContentTypeService contentTypeService,
            IPapermoonContentTypeService papermoonContentTypeService,
            IPapermoonContentTypeContainerService papermoonContentTypeContainerService,
            IPapermoonTemplateService papermoonTemplateService)
            : base(
                contentTypeService,
                papermoonContentTypeService,
                papermoonContentTypeContainerService,
                papermoonTemplateService) { }

        public IContentType GetComposition()
        {
            Composition = ContentTypeService.Get("aldusBlogComposition");

            if (Composition == null)
            {
                Composition = new ContentType(AldusCompositionsContainer.Id);
            }

            Composition.Name = "Aldus Blog Composition";
            Composition.Alias = "aldusBlogComposition";
            Composition.Description = "A composition for the Aldus blog listing.";
            Composition.Icon = "icon-settings";

            return Composition;
        }

        public IContentType GetContentType()
        {
            ContentType = ContentTypeService.Get("aldusBlog");

            if (ContentType == null)
            {
                ContentType = new ContentType(AldusContainer.Id);
            }

            ContentType.Name = "Blog";
            ContentType.Alias = "aldusBlog";
            ContentType.Description = "Aldus blog listing.";
            ContentType.Icon = "icon-article";

            ContentType.AllowedTemplates = PapermoonTemplateService.Get(new [] { "AldusBlog" });

            ContentType.SetDefaultTemplate(ContentType.AllowedTemplates.First());

            ContentType.ContentTypeComposition =
                PapermoonContentTypeService.GetCompositions(ContentType, new List<string> {"aldusBlogComposition"});

            return ContentType;
        }
    }
}

Furthermore, I've tried adding a call to .Returns but still see the error. I've tried the following ways:

After the callback:

_blogContentTypeFactory
    .Setup(f => f.GetComposition())
    .Callback(() => { contentType.SetupProperty(ct => ct.Alias == alias); })
    .Returns(contentType.Object);

Assignment as part of the return:

_blogContentTypeFactory
    .Setup(f => f.GetComposition())
    .Returns(contentType.SetupProperty(ct => ct.Alias, alias).Object);
0Neji
  • 1,038
  • 1
  • 14
  • 36
  • Have you tried debugging and see where the Null Reference is? Are you passing the Mocked services and factory into the concrete class? – JEV Aug 23 '19 at 13:16

3 Answers3

0

Is it because you are missing the .Returns usage on the Mock factory instead?

    contentType.SetupProperty(ct => ct.Alias, alias)

   _blogContentTypeFactory
        .Setup(f => f.GetComposition())
        .Returns(contentType.SetupProperty);

Hard to tell without seeing more code around the instantiation of the concrete class.

JEV
  • 2,494
  • 4
  • 33
  • 47
  • I've tried adding `.Returns` in a couple of ways, could 100% be doing it wrong! Updated the question with info. – 0Neji Aug 23 '19 at 15:58
0

There are a few ways to configure the mock and its property.

The following uses the LINQ to Mocks appraoch

[Test]
[TestCase("aldusBlogComposition")]
public void Initialise_WhenCalled_SavesComposition(string alias) {
    //Arrange
    IContentType contentType = Mock.Of<IContentType>(_ => _.ALias == alias);

    _blogContentTypeFactory
        .Setup(_ => _.GetComposition())
        .Returns(contentType);

    //Act
    _component.Initialize();

    //Assert
    _contentTypeService.Verify(s => s.Save(It.Is<IContentType>(ct => ct.Alias == alias), It.IsAny<int>()), Times.Once);
}

You could have even verified that it was the same returned instance that was passed

//...omitted for brevity

//Assert
_contentTypeService.Verify(s => s.Save(contentType, It.IsAny<int>()), Times.Once);

//...
Nkosi
  • 235,767
  • 35
  • 427
  • 472
0

Turns out that Verify set up was right but a null value was being returned from the GetContentType method, I just need to set up a return:

_blogContentTypeFactory
    .Setup(f => f.GetContentType())
    .Returns(Mock.Of<IContentType>());
0Neji
  • 1,038
  • 1
  • 14
  • 36
  • it looks like my answer was literally what you used? Please could you accept that? – JEV Aug 27 '19 at 08:47