Unit Testing Umbraco

    These examples are for Umbraco 8+ and they rely on NUnit and Moq.

    Mocking

    When testing components in Umbraco, especially controllers, there are a few dependencies that needs to be mocked / faked in order to get your unit tests running. Every Umbraco controller has two constructors: one empty constructor without any parameters for anyone not interested in unit testing or dependency injections, and one with full constructor injection which contains all parameters needed for proper unit testing. A lot of these dependencies are interfaces, which are simply mocked using Mock.Of<>, but there are still a few explicit non-interface dependencies that needs to be faked. In this documentation all mocks and fakes have been placed in a base class to avoid having to repeat this setup in every test class.

    public abstract class UmbracoBaseTest 
    {
        public ServiceContext ServiceContext;
        public MembershipHelper MembershipHelper;
        public UmbracoHelper UmbracoHelper;
    
        public Mock<ICultureDictionary> CultureDictionary;
        public Mock<ICultureDictionaryFactory> CultureDictionaryFactory;
        public Mock<IPublishedContentQuery> PublichedContentQuery;
    
        [SetUp]
        public virtual void SetUp()
        {
            this.SetupCultureDictionaries();
            this.SetupPublishedContentQuerying();
    
            this.ServiceContext = ServiceContext.CreatePartial();
            this.MembershipHelper = new MembershipHelper(Mock.Of<HttpContextBase>(), Mock.Of<IPublishedMemberCache>(), Mock.Of<MembershipProvider>(), 
            Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), AppCaches.NoCache, Mock.Of<ILogger>());
            this.UmbracoHelper = new UmbracoHelper(Mock.Of<IPublishedContent>(), Mock.Of<ITagQuery>(), this.CultureDictionaryFactory.Object, 
            Mock.Of<IUmbracoComponentRenderer>(), this.PublichedContentQuery.Object, this.MembershipHelper);
        }
    
        public virtual void SetupCultureDictionaries()
        {
            this.CultureDictionary = new Mock<ICultureDictionary>();
            this.CultureDictionaryFactory = new Mock<ICultureDictionaryFactory>();
            this.CultureDictionaryFactory.Setup(x => x.CreateDictionary()).Returns(this.CultureDictionary.Object);
        }
    
        public virtual void SetupPublishedContentQuerying()
        {
            this.PublichedContentQuery = new Mock<IPublishedContentQuery>();
        }
    
        public void SetupPropertyValue(Mock<IPublishedContent> publishedContentMock, string alias, object value, string culture = null, string segment = null)
        {
            var property = new Mock<IPublishedProperty>();
            property.Setup(x => x.Alias).Returns(alias);
            property.Setup(x => x.GetValue(culture, segment)).Returns(value);
            property.Setup(x => x.HasValue(culture, segment)).Returns(value != null);
            publishedContentMock.Setup(x => x.GetProperty(alias)).Returns(property.Object);
        }
    }
    

    Note that ServiceContext.CreatePartial() has several optional parameters, and by naming them you only need to mock the dependencies that you actually need, for example: ServiceContext.CreatePartial(contentService: Mock.Of<IContentService>());

    Testing a ContentModel

    See Reference documentation on Returning a view with a custom model.

    public class MyCustomViewModel : ContentModel
    {
        public MyCustomViewModel(IPublishedContent content) : base(content) { }
    
        public string Heading => this.Content.Value<string>(nameof(Heading));
    }
    
    [TestFixture]
    public class MyCustomModelTests : UmbracoBaseTest
    {
        [SetUp]
        public override void SetUp()
        {
            base.SetUp();
        }
    
        [Test]
        [TestCase("", "")]
        [TestCase("My Heading", "My Heading")]
        [TestCase("Another Heading", "Another Heading")]
        public void GivenPublishedContent_WhenGetHeading_ThenReturnCustomViewModelWithHeadingValue(string value, string expected)
        {
            var publishedContent = new Mock<IPublishedContent>();
            base.SetupPropertyValue(publishedContent, nameof(MyCustomViewModel.Heading), value);
            
            var model = new MyCustomViewModel(publishedContent.Object);
            
            Assert.AreEqual(expected, model.Heading);
        }
    }
    

    Testing a RenderMvcController

    See Reference documentation for Custom controllers (Hijacking Umbraco Routes).

    public class HomeController : RenderMvcController
    {
        public HomeController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext serviceContext, AppCaches appCaches, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContextAccessor, serviceContext, appCaches, profilingLogger, umbracoHelper) { }
    
        public override ActionResult Index(ContentModel model)
        {
            var myCustomModel = new MyCustomModel(model.Content);
    
            myCustomModel.MyProperty1 = "Hello World";
    
            return View(myCustomModel);
        }
    }
    
    public class MyCustomModel : ContentModel
    {
        public MyCustomModel(IPublishedContent content) : base(content) { }
    
        public string MyProperty1 { get; set; }
    }
    
    [TestFixture]
    public class HomeControllerTests : UmbracoBaseTest
    {
        private HomeController controller;
    
        [SetUp]
        public override void SetUp()
        {
            base.SetUp();
            this.controller = new HomeController(Mock.Of<IGlobalSettings>(), Mock.Of<IUmbracoContextAccessor>(), base.ServiceContext, AppCaches.NoCache, Mock.Of<IProfilingLogger>(), base.UmbracoHelper);
        }
    
        [Test]
        public void WhenIndexAction_ThenResultIsIsAssignableFromContentResult()
        {
            var model = new ContentModel(new Mock<IPublishedContent>().Object);
    
            var result = this.controller.Index(model);
    
            Assert.IsAssignableFrom<ViewResult>(result);
        }
    
        [Test]
        public void GivenContentModel_WhenIndex_ThenReturnViewModelWithMyProperty()
        {
            var model = new ContentModel(new Mock<IPublishedContent>().Object);
    
            var result = (MyCustomModel)((ViewResult)this.controller.Index(model)).Model;
    
            Assert.AreEqual("Hello World", result.MyProperty1);
        }
    }
    

    Testing a SurfaceController

    See Reference documentation on SurfaceControllers.

    public class MySurfaceController : SurfaceController
    {
        public MySurfaceController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory umbracoDatabaseFactory, ServiceContext serviceContext, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(umbracoContextAccessor, umbracoDatabaseFactory, serviceContext, appCaches, logger, profilingLogger, umbracoHelper) { }
    
        public ActionResult Index()
        {
            return Content("Hello World");
        }
    }
    
    [TestFixture]
    public class MySurfaceControllerTests : UmbracoBaseTest
    {
        private MySurfaceController controller;
    
        [SetUp]
        public override void SetUp()
        {
            base.SetUp();
            this.controller = new MySurfaceController(Mock.Of<IUmbracoContextAccessor>(), Mock.Of<IUmbracoDatabaseFactory>(), base.ServiceContext, AppCaches.NoCache, Mock.Of<ILogger>(), Mock.Of<IProfilingLogger>(), base.UmbracoHelper);
        }
    
        [Test]
        public void WhenIndexAction_ThenResultIsIsAssignableFromContentResult()
        {
            var result = this.controller.Index();
    
            Assert.IsAssignableFrom<ContentResult>(result);
        }
    
        [Test]
        public void GivenResultIsAssignableFromContentResult_WhenIndexAction_ThenContentIsExpected()
        {
            var result = (ContentResult)this.controller.Index();
    
            Assert.AreEqual("Hello World", result.Content);
        }
    }
    

    Testing ICultureDictionary using the UmbracoHelper

    See Core documentation on the interface ICultureDictionary.

    public class HomeController : RenderMvcController
    {
        public HomeController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext serviceContext, AppCaches appCaches, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContextAccessor, serviceContext, appCaches, profilingLogger, umbracoHelper) { }
    
        public override ActionResult Index(ContentModel model)
        {
            var myCustomModel = new MyCustomModel(model.Content)
            {
                MyProperty1 = this.Umbraco.GetDictionaryValue("myDictionaryKey")
            };
    
            return View(myCustomModel);
        }
    }
    
    [TestFixture]
    public class HomeControllerTests : UmbracoBaseTest
    {
        private HomeController controller;
        private Mock<ICultureDictionary> cultureDictionary;
    
        [SetUp]
        public override void SetUp()
        {
            base.SetUp();
            this.controller = new HomeController(Mock.Of<IGlobalSettings>(), Mock.Of<IUmbracoContextAccessor>(), base.ServiceContext, AppCaches.NoCache, Mock.Of<IProfilingLogger>(), base.UmbracoHelper);
        }
    
        [Test]
        [TestCase("myDictionaryKey", "myDictionaryValue")]
        public void GivenMyDictionaryKey_WhenIndex_ThenReturnViewModelWithMyPropertyDictionaryValue(string key, string expected)
        {
            var model = new ContentModel(new Mock<IPublishedContent>().Object);
            base.CultureDictionary.Setup(x => x[key]).Returns(expected);
    
            var result = (MyCustomModel)((ViewResult)this.controller.Index(model)).Model;
    
            Assert.AreEqual(expected, result.MyProperty1);
        }
    }
    

    Testing IPublishedContentQuery using the UmbracoHelper

    See Core documentation on the interface IPublishedContentQuery.

    public class MyCustomController : RenderMvcController
    {
        public MyCustomController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext serviceContext, AppCaches appCaches, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContextAccessor, serviceContext, appCaches, profilingLogger, umbracoHelper) { }
    
        public override ActionResult Index(ContentModel model)
        {
            var myCustomModel = new MyOtherCustomModel(model.Content)
            {
                OtherContent = this.Umbraco.Content(1062)
            };
    
            return View(myCustomModel);
        }
    }
    
    public class MyOtherCustomModel : ContentModel 
    {
        public MyOtherCustomModel(IPublishedContent content) : base(content) { }
        public IPublishedContent OtherContent { get; set; }
    }
    
    [TestFixture]
    public class MyCustomControllerTests : UmbracoBaseTest
    {
        private MyCustomController controller;
    
        [SetUp]
        public override void SetUp()
        {
            base.SetUp();
            this.controller = new MyCustomController(Mock.Of<IGlobalSettings>(), Mock.Of<IUmbracoContextAccessor>(), base.ServiceContext, AppCaches.NoCache, Mock.Of<IProfilingLogger>(), base.UmbracoHelper);
        }
    
        [Test]
        public void GivenContentQueryReturnsOtherContent_WhenIndex_ThenReturnViewModelWithOtherContent()
        {
            var currentContent = new ContentModel(new Mock<IPublishedContent>().Object);
            var otherContent = Mock.Of<IPublishedContent>();
            base.PublichedContentQuery.Setup(x => x.Content(1062)).Returns(otherContent);
    
            var result = (MyOtherCustomModel)((ViewResult)this.controller.Index(currentContent)).Model;
    
            Assert.AreEqual(otherContent, result.OtherContent);
        }
    }