Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Gabor Ferencz 36 posts 167 karma points
    Apr 03, 2020 @ 08:37
    Gabor Ferencz
    0

    How to test Controllers with CurrentPage in V8

    Hi,

    I'm trying to set up a unit test for a renderMVCController and a SurfaceController. When I try to access the CurrentPage property on the surfacecontroller, I get an error saying that there is no routecontext.

    I have then tried to set my UmbracoContextAccessor like so:

    public abstract class UmbracoBaseTest : BaseWebTest
    {
        public ServiceContext ServiceContext;
        public MembershipHelper MembershipHelper;
        public UmbracoHelper UmbracoHelper;
        public UmbracoMapper UmbracoMapper;
        public IUmbracoContextAccessor UmbracoContextAccessor;
    
        public Mock<ICultureDictionary> CultureDictionary;
        public Mock<ICultureDictionaryFactory> CultureDictionaryFactory;
        public Mock<IPublishedContentQuery> PublishedContentQuery;
    
        public Mock<HttpContextBase> HttpContext;
        public Mock<IMemberService> memberService;
        public Mock<IPublishedMemberCache> memberCache;
    
        [SetUp]
        public virtual void SetUp()
        {
    
            this.SetupHttpContext();
            this.SetupCultureDictionaries();
            this.SetupPublishedContentQuerying();
            this.SetupMembership();
            var settings = SettingsForTests.GenerateMockUmbracoSettings();
            var globalSettings = SettingsForTests.GenerateMockUmbracoSettings();
    
            this.ServiceContext = ServiceContext.CreatePartial();
            this.UmbracoHelper = new UmbracoHelper(Mock.Of<IPublishedContent>(), Mock.Of<ITagQuery>(), this.CultureDictionaryFactory.Object, Mock.Of<IUmbracoComponentRenderer>(), this.PublishedContentQuery.Object, this.MembershipHelper);
            this.UmbracoMapper = new UmbracoMapper(new MapDefinitionCollection(new List<IMapDefinition>()));
    
            var umbracoContextAccessor = new Mock<IUmbracoContextAccessor>();
    
            var umbracoContext = GetUmbracoContext("http://localhost", -1, setSingleton: true);
            umbracoContextAccessor.Setup(t => t.UmbracoContext)
                .Returns(umbracoContext);
    
            this.UmbracoContextAccessor = umbracoContextAccessor.Object;
        }
    

    But this does not seem to work. I get an error:

    Umbraco.Core.Exceptions.PanicException : Could not resolve the running test fixture from type name RedCarnation.Web.Tests.Controllers.MasterControllerTests. To use base classes from Umbraco.Tests, add your test assembly to TestOptionAttributeBase.ScanAssemblies

    Any idea how I can get this working?

    Thanks,Gabor

  • Gabor Ferencz 36 posts 167 karma points
    Apr 07, 2020 @ 06:41
    Gabor Ferencz
    0

    Can anyone help out with the above? Is there any documentation on how to test controllers where we are using the CurrentPage property?

  • Gabor Ferencz 36 posts 167 karma points
    Apr 08, 2020 @ 07:05
    Gabor Ferencz
    100

    Ok, so I think I figured it out. Passing in the ContentModel into the Controller Index action will serve just like the CurrentPage.ID, and is testable. I still have much to learn.

  • Armend Imeri 6 posts 74 karma points
    Jun 16, 2020 @ 10:19
    Armend Imeri
    0

    Hello Gabor, How did you manage to get around this? My controller actions don't take in parameters they are usually empty and CurrentPage is being filled in automatically. When I pass in it asks for me to either generate a new action that takes in ContentModel or add contentmodel to my existing action. Could you share any insight you might have gained from this? I have been trying to add unit testing to an umbraco project it's been quite a journey just to get the tests to fail up until now

    How my controller action looks:

     public ActionResult IndexNew()
        {
            ViewBag.Dictionary = GetIndexDictionary();
    
            var home = CurrentPage.Root();
    
            var heroimage = CurrentPage.Value<IPublishedContent>("heroImage");
            ViewBag.heroImageUrl = heroimage != null ? heroimage.GetCropUrl(1920, 1080) : "/assets/images/placeholders/Article-Placeholder.jpg";
    
            var market = Translate.MARKET(ViewBag.Dictionary["languageCodeDict"]);
    
            DDCApiModel api = new DDCApiModel();
            ViewBag.CountResult = api.CountAllProducts(market);
    
            return PartialView(string.Format("{0}IndexNew.cshtml", ViewPath), CurrentPage);
        }
    
  • Gabor Ferencz 36 posts 167 karma points
    Jun 16, 2020 @ 12:18
    Gabor Ferencz
    0

    Hi Armend,

    You have to separate things out a bit to get unit testing to work. For example - CurrentPage Requires an UmbracoContext, which I haven't managed to mock.

    Changing it to:

     public ActionResult IndexNew(ContentModel currentPage)
    {
        ViewBag.Dictionary = GetIndexDictionary();
    
        var home = currentPage.Root();
    
        var heroimage = CurrentPage.Value<IPublishedContent>("heroImage");
        ViewBag.heroImageUrl = heroimage != null ? heroimage.GetCropUrl(1920, 1080) : "/assets/images/placeholders/Article-Placeholder.jpg";
    
        var market = Translate.MARKET(ViewBag.Dictionary["languageCodeDict"]);
    
        DDCApiModel api = new DDCApiModel();
        ViewBag.CountResult = api.CountAllProducts(market);
    
        return PartialView(string.Format("{0}IndexNew.cshtml", ViewPath), CurrentPage);
    }
    

    Will be the same as using the CurrentPage property, except this way you can mock your contentModel that you will be passing in:

      var result = (BrandHomePageModel)((ViewResult)this.controller.Index(new ContentModel(Mock.Of<IPublishedContent>()))).Model;
    

    It's then up to you to test the logic.

    Hop this makes sense Gabor

  • Armend Imeri 6 posts 74 karma points
    Jun 17, 2020 @ 10:51
    Armend Imeri
    0

    Understood, How do you call the function then because it now requires a parameter so we would need to pass in ContentModel when trying to render the page in the frontend

  • Gabor Ferencz 36 posts 167 karma points
    Jun 17, 2020 @ 17:44
    Gabor Ferencz
    0

    What front-end do you use?

    I mean, we use Vue.JS, and we simply route to /PageController/Index and that being a RenderMVCController will work for a page with alias page. we then return json to vuew that renders the FE.

    What front end do you use? If it's simple MVC, then just route to the index method, and Umbraco build the contentModel for you.

  • Armend Imeri 6 posts 74 karma points
    Jun 18, 2020 @ 12:06
    Armend Imeri
    0

    We just use simple MVC. I understood that and managed to get it working but my tests still don't run throwing factory not set.

    I did take UmbracoBaseTest from umbraco documentation but it seems yours has some extra code which is:

     var umbracoContext = GetUmbracoContext("http://localhost", -1, setSingleton: true);
            umbracoContextAccessor.Setup(t => t.UmbracoContext)
                .Returns(umbracoContext);
    
            this.UmbracoContextAccessor = umbracoContextAccessor.Object;
    

    What is GetUmbracoContext ? Is this why my test is throw "Factory not set"? What I've tried in Test Class

    private ProductsController controller;
            private readonly Mock<IPublishedContent> currentPage;
            private Mock<IFactory> Factory;
            public ProductControllerTests()
            {
                base.SetUp();
                Factory = new Mock<IFactory>();
                this.currentPage = new Mock<IPublishedContent>();
                this.umbracoHelper = new UmbracoHelper(this.currentPage.Object, Mock.Of<ITagQuery>(), this.CultureDictionaryFactory.Object, Mock.Of<IUmbracoComponentRenderer>(), this.PublishedContentQuery.Object, this.MembershipHelper);
    
                this.controller = new ProductsController(Mock.Of<IUmbracoContextAccessor>(), Mock.Of<IUmbracoDatabaseFactory>(), base.ServiceContext, AppCaches.NoCache, Mock.Of<Umbraco.Core.Logging.ILogger>(), Mock.Of<Umbraco.Core.Logging.IProfilingLogger>(), base.umbracoHelper);
            }
    
    
            [Test]
            public void WhenIndexAction_ThenResultIsIsAssignableFromContentResult()
            {
                var productsPage = new Mock<IPublishedContent>();
    
    
                var model = new Umbraco.Web.Models.ContentModel(new Mock<IPublishedContent>().Object);
    
    
                var result = this.controller.IndexMain(model.Content) as ViewResult;
    
                var productPage = (Products)result.ViewData.Model;
                Assert.AreEqual(productPage.Name, "Products");
            }
    

    Controller:

    private readonly UmbracoHelper umbracoHelper;
            public ProductsController(IUmbracoContextAccessor umbracoContextAccessor, Umbraco.Core.Persistence.IUmbracoDatabaseFactory umbracoDatabaseFactory, Umbraco.Core.Services.ServiceContext serviceContext, Umbraco.Core.Cache.AppCaches appCaches, Umbraco.Core.Logging.ILogger logger, Umbraco.Core.Logging.IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(umbracoContextAccessor, umbracoDatabaseFactory, serviceContext, appCaches, logger, profilingLogger, umbracoHelper) {
                this.umbracoHelper = umbracoHelper;
            }
            public ActionResult IndexMain(IPublishedContent content)
            {
                ViewBag.Dictionary = GetIndexDictionary();           
    
                var heroimage = content.Value<IPublishedContent>("heroImage");
                ViewBag.heroImageUrl = heroimage != null ? heroimage.GetCropUrl(1920, 1080) : "/assets/images/placeholders/Article-Placeholder.jpg";
    
                var market = Translate.MARKET(ViewBag.Dictionary["languageCodeDict"]);
    
                DDCApiModel api = new DDCApiModel();
                ViewBag.CountResult = api.CountAllProducts(market);
    
                return PartialView(string.Format("{0}Index.cshtml", ViewPath), content);
            }
    

    Btw installing Umbraco.Tests crashes our Umbraco installation and umbraco fails to boot Umbraco.Core.Exceptions.BootFailedException: Boot failed.

    -> System.Reflection.ReflectionTypeLoadException: Could not load all types from "Umbraco.Tests
    
  • Gabor Ferencz 36 posts 167 karma points
    Jun 18, 2020 @ 12:35
    Gabor Ferencz
    0

    I don't think I managed to get Umbraco.Tests working either...

    So my controller constructor is:

      public Bp02BrandStandardController(IBrandStandardPageRepository repo, IUmbracoContextAccessor umbracoContextAccessor,
                IGlobalSettings globalSettings, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger,
                UmbracoHelper umbracoHelper)
                : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger, umbracoHelper)
            {
                _brandStandardPageRepository = repo;
            }
    

    This is so you can pass in some parameters when testing the controller.

    This is my controller test class

      public class BrandStandardPageControllerTests : UmbracoBaseTest
    {
        private Bp02BrandStandardController controller;
        private Mock<IBrandStandardPageRepository> _repository;
    
         [SetUp]
        public override void SetUp()
        {
            base.SetUp();
            _repository = new Mock<IBrandStandardPageRepository>();
            _repository.Setup(t => t.GetPage(It.IsAny<object>())).Returns(new PageModel());
    
            this.controller = new Bp02BrandStandardController(_repository.Object,
                UmbracoContextAccessor, Mock.Of<IGlobalSettings>(), base.ServiceContext, AppCaches.NoCache, Mock.Of<IProfilingLogger>(), base.UmbracoHelper);
    
    
        }
    
        [Test]
        public void GivenContentModel_WhenControllerIsCalled_BrandStandardPageIsReturned()
        {
    
            var result = (PageModel)((ViewResult)this.controller.Index(new ContentModel(Mock.Of<IPublishedContent>()))).Model;
            Assert.IsNotNull(result);
        }
    }
    

    And my base class setup is:

     [SetUp]
        public virtual void SetUp()
        {
    
            this.SetupHttpContext();
            this.SetupCultureDictionaries();
            this.SetupPublishedContentQuerying();
            this.SetupMembership();
      } public virtual void SetupHttpContext()
        {
            this.HttpContext = new Mock<HttpContextBase>();
        }
    
        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.PublishedContentQuery = new Mock<IPublishedContentQuery>();
        }
    
        public virtual void SetupMembership()
        {
            this.memberService = new Mock<IMemberService>();
            var memberTypeService = Mock.Of<IMemberTypeService>();
            var membershipProvider = new MembersMembershipProvider(memberService.Object, memberTypeService);
    
            this.memberCache = new Mock<IPublishedMemberCache>();
            this.MembershipHelper = new MembershipHelper(this.HttpContext.Object, this.memberCache.Object, membershipProvider, Mock.Of<RoleProvider>(), memberService.Object, memberTypeService, Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), AppCaches.NoCache, Mock.Of<ILogger>());
        }
    
        public static 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);
        }
    
        public static void SetupPropertyValue(Mock<IPublishedElement> 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);
        }
    

    At its most basic this is what you need to run a test. When you have a no factory set, then it means that something is trying to access the umbracoContext. Do away with any code that tries to do this. Abstract it out, mock it away, in order to get it to work.

Please Sign in or register to post replies

Write your reply to:

Draft