设置模拟对象属性,然后验证它是否在方法调用中使用

时间:2019-08-23 13:13:58

标签: c# unit-testing nunit moq

我正在尝试创建一个测试,以验证是否调用了特定方法。该方法接受两个参数,我想检查是否已使用设置了特定属性的对象调用它。

代码如下:

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

    _umbracoContentTypeService.Save(blogContentTypeComposition);
}

这将从工厂获取构图,然后在Save方法中使用它。在测试中,blogContentTypeComposition应该具有一个称为alias的属性,该属性设置为aldusBlogCompositionblogContentTypeComposition.Alias)。

这是测试代码:

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

此代码创建一个模拟IContentType,并在调用GetComposition时将别名设置为aldusBlogComposition。然后Verify应该检查Save方法是否运行一次,第一个参数是IContentType,别名属性设置为aldusBlogComposition

当我运行测试时,这会引发一个错误(如下),我怀疑这表明该模拟未在Verify方法调用中使用。

Object reference not set to an instance of an object.

我想念什么?

编辑:

该错误是作为contentTypeService.Verify(s => s.Save(It.Is<IContentType>(ct => ct.Alias == alias), It.IsAny<int>()), Times.Once);调用的一部分引发的。我唯一能看到的是nullct-如果仅将其交换为It.IsAny<IContentType>(),就不会引发错误。我了解什么是空引用,但我不明白为什么参数为空。

完整类供参考:

测试类:

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

组件类:

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() { }
    }
}

以及博客工厂类:

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

最后,内容类型为工厂类:

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

此外,我尝试将通话添加到.Returns,但仍然看到错误。我尝试了以下方法:

回调之后:

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

分配作为回报的一部分:

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

3 个答案:

答案 0 :(得分:0)

是因为您错过了.Returns工厂的Mock用法吗?

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

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

很难说出具体类的实例周围没有更多的代码。

答案 1 :(得分:0)

有几种方法可以配置模拟及其属性。

以下内容使用LINQ to Mocks方法

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

您甚至可以验证它是否与传递的返回实例相同

//...omitted for brevity

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

//...

答案 2 :(得分:0)

结果证明Verify的设置是正确的,但是从GetContentType方法返回了一个空值,我只需要设置一个返回值:

_blogContentTypeFactory
    .Setup(f => f.GetContentType())
    .Returns(Mock.Of<IContentType>());