Copied to clipboard

Flag this post as spam?

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


  • Poornima Nayar 106 posts 276 karma points MVP 5x c-trib
    May 14, 2020 @ 07:58
    Poornima Nayar
    0

    Unit Testing Surface Controllers

    Hi,

    I am trying to implement unit testing for a surface controller. The GET method tries to read some properties of the CurrentPage and POST method tries to redirect to the ChildPage of the CurrentPage. The problem I am encountering is I can never get the UmbracoContext in my unit tests. Has someone encountered and solved this? Any help much appreciated

    This is an example of what my code will do on POST

    public ActionResult PostRegistrationForm(ChosenRegistrationViewModel model, HttpPostedFileBase photo)
    {
    
    //do some logic and if successful redirect
    
    
    var thankYouPage = CurrentPage.ChildrenOfType(ChosenThankYouPage.ModelTypeAlias).FirstOrDefault();
    return this.RedirectToUmbracoPage(thankYouPage, "eventId=" + model.SignUpEventId.ToString() + "&registrationId=" + model.Id.ToString());
    }
    
  • Dennis Adolfi 1082 posts 6446 karma points MVP 5x c-trib
    May 14, 2020 @ 08:22
    Dennis Adolfi
    0

    Hi Poornima.

    Instead of using CurrentPage, use the UmbracoHelper.AssignedContentItem. Easier to mock.

    Instructions on how tro mock the UmbracoHelper is found here: https://our.umbraco.com/documentation/Implementation/Unit-Testing/

    Cheers!

  • Poornima Nayar 106 posts 276 karma points MVP 5x c-trib
    May 14, 2020 @ 08:26
    Poornima Nayar
    0

    Thanks Dennis, will give it a shot..

  • Dennis Adolfi 1082 posts 6446 karma points MVP 5x c-trib
    May 18, 2020 @ 05:45
    Dennis Adolfi
    100

    Hi Poornima. Based on your example code (and our DM conversation on LinkedIn) it created an example of how a test for your example could look like.

    The base class UmbracoBaseTest is the same base class I mention on this page: https://our.umbraco.com/documentation/Implementation/Unit-Testing/

    public class TestingTests : UmbracoBaseTest
        {
            private readonly UmbracoHelper umbracoHelper;
            private readonly Mock<IPublishedContent> currentPage;
            private readonly RegistrationController controller;
    
            public TestingTests()
            {
                base.SetUp();
                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.MembershipHelperImplementation);
                this.controller = new RegistrationController(Mock.Of<IUmbracoContextAccessor>(), Mock.Of<IUmbracoDatabaseFactory>(), base.ServiceContext, AppCaches.NoCache, Mock.Of<ILogger>(), Mock.Of<IProfilingLogger>(), umbracoHelper);
            }
    
            [Fact]
            public void Given_SuccessfullRegistration_When_PostRegistrationForm_Then_RedirectToThankYouPageWithExpectedQueryString()
            {
                var thankYouPageType = new Mock<IPublishedContentType>();
                thankYouPageType.Setup(x => x.Alias).Returns("thankYouPage");
    
                var thankYouPage = new Mock<IPublishedContent>();
                thankYouPage.Setup(x => x.Id).Returns(123);
                thankYouPage.Setup(x => x.Url).Returns("/thankyou");
                thankYouPage.Setup(x => x.ContentType).Returns(thankYouPageType.Object);
    
                this.currentPage.Setup(x => x.ChildrenForAllCultures).Returns(new List<IPublishedContent>() { thankYouPage.Object });
    
                var registrationModel = new ChosenRegistrationViewModel()
                {
                    Id = 456,
                    SignUpEventId = 789
                };
    
                var result = (RedirectResult)this.controller.PostRegistrationForm(registrationModel);
    
                result.Url.ShouldBe("/thankyou?eventId=789&registrationId=456");
            }
        }
    
        public class RegistrationController : SurfaceController
        {
            private readonly UmbracoHelper umbracoHelper;
    
            public RegistrationController(IUmbracoContextAccessor umbracoContextAccessor,
                IUmbracoDatabaseFactory umbracoDatabaseFactory, ServiceContext serviceContext, AppCaches appCaches,
                ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(
                umbracoContextAccessor, umbracoDatabaseFactory, serviceContext, appCaches, logger, profilingLogger,
                umbracoHelper)
            {
                this.umbracoHelper = umbracoHelper;
            }
    
            [HttpPost]
            public ActionResult PostRegistrationForm(ChosenRegistrationViewModel model)
            {
                //do some logic and if successful redirect
    
                var thankYouPage = this.umbracoHelper.AssignedContentItem.ChildrenOfType("thankYouPage").FirstOrDefault();
                return Redirect(string.Format($"{thankYouPage?.Url}?eventId={model.SignUpEventId}&registrationId={model.Id}"));
            }
        }
    
        public class ChosenRegistrationViewModel
        {
            public int Id { get; set; }
            public int SignUpEventId { get; set; }
        }
    

    I ended up ditching RedirectToUmbracoPageResult because it turned out to be quite hard to Assert (queryStringValues is a private field, Url fields uses static resolver Current to resolve current page instead of DI), instead I used plain old return Redirect(url); Hope this works for you.

    Have a great day and stay safe!

  • Poornima Nayar 106 posts 276 karma points MVP 5x c-trib
    May 18, 2020 @ 08:34
    Poornima Nayar
    1

    Thanks a lot Dennis. Much much appreciated :-)

  • Isaac Meyers 8 posts 88 karma points
    Aug 17, 2023 @ 14:38
    Isaac Meyers
    0

    Hi there,

    I am writing test code for Umbraco 10 and I was struggling with this exact same issue and I stumbled across this thread. The base test class seemed to be Umbraco 8.

    Did anyone have an answer for the more recent Umbraco versions?

  • Dennis Adolfi 1082 posts 6446 karma points MVP 5x c-trib
    Aug 17, 2023 @ 16:56
    Dennis Adolfi
    0

    Hi Isaac. You are correct, the the base class mentioned in this thread does not exist any more in v9+ since there was very little plumbing needed to perform testing in v9+ we chose to skip the base class and instead I lace the little plumbing in each implementation.

    What is it specifically that you are struggling with, maybe I can help?

  • Isaac Meyers 8 posts 88 karma points
    Aug 17, 2023 @ 17:21
    Isaac Meyers
    0

    I was struggling to get the value of CurrentPage to be mocked correctly when testing the following function in my SurfaceController:

    enter image description here

    I was able to finally get it to work by mocking and setting up the content Features in a way that UmbracoRouteValues would be set. It seems very messy and there is probably a better solution but it's at least at a point where that gets mocked.

    enter image description here

    Now I am struggling to get CurrentPage.Value

    I am trying to use the following helper function:

    enter image description here

    which I found here: https://adolfi.dev/blog/mocking-property-values-umbraco/

    If you have any insight on getting Properties and their Value getters setup, that would be very helpful!

    Thanks, Isaac

  • Dennis Adolfi 1082 posts 6446 karma points MVP 5x c-trib
    Aug 18, 2023 @ 07:27
    Dennis Adolfi
    0

    Yes the reason that everything becomes messy is because you are using CurrentPage it it is a bit complicated when working with unit testing.

    I usually try to avoid CurrentPage and instead inject the currentPage through my Action like this: enter image description here

    Then it becomes a lot less complicated to mock and inject this from my unit tests, like this:

    enter image description here

    content in this case is just a mocked IPublishedContent interface.

    So this can probably reduce some code in your project.

    Regarding the Value getters I have a slight memory that the extension method .Value has an underlying dependency that was a bit messy to mock (cant remember which one sorry you have to dig in to the Core).

    There is however a easier way to avoid this. Instead of using the extension method you can use the GetValue() method on the Property like I am doing here: https://github.com/Adolfi/Umbraco-v10-Unit-Testing/blob/main/Umbraco10Testing.Tests/Features/PageViewModel.cs#L10C89-L10C89

    That should work with the mocking you have screenshoted.

  • Dennis Adolfi 1082 posts 6446 karma points MVP 5x c-trib
    Aug 18, 2023 @ 07:29
    Dennis Adolfi
    0

    Also if you didn't already find it, I have an example project in GitHub with a bunch of Umbraco 9-10 unit tests: https://github.com/Adolfi/Umbraco-v10-Unit-Testing

    Hopefully it might be useful as inspiration for you.

    Cheers!

Please Sign in or register to post replies

Write your reply to:

Draft