简体   繁体   中英

How to Unit Test a GlassController Action which Returns a View Taking a Model

I'm a sitecore developer and I want to create a sample sitecore helix unit testing project for testing out our "HomeBottomContentController" controller:

    public class HomeBottomContentController : GlassController
    {
        private readonly ISitecoreContext _iSitecoreContext;
        public HomeBottomContentController(ISitecoreContext iSitecoreContext)
        {
            _iSitecoreContext = iSitecoreContext;
        }

        public override ActionResult Index()
        {
            var model = _iSitecoreContext.GetCurrentItem<Home_Control>();
            return View("~/Views/HomeBottomContent/HomeBottomContent.cshtml", model);
        }
    }

I have created a WTW.Feature.HomeBottomContent.Tests project, for the purpose of testing this entire component using helix unit testing. In it I have a UnitTest1.cs file with following:

namespace WTW.Feature.HomeBottomContent.Tests
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void Test_ISitecoreContextInsertion()
        {
            var iSitecoreContext = Mock.Of<Glass.Mapper.Sc.ISitecoreContext>();
            HomeBottomContentController controllerUnderTest = new HomeBottomContentController(iSitecoreContext);
            var result = controllerUnderTest.Index() as ViewResult;
            Assert.IsNotNull(result);
        }
    }
}

This test does pass, meaning "result" is NOT null; however, the problem is when I step into the Index() code, I see that the "model" variable is NULL when we do

    var model = _iSitecoreContext.GetCurrentItem<Home_Control>();

My question is, how exactly do I change this code to make sure that the "model" in that line does not become null? How do I "mock" an item in unit test code for the _iSitecoreContext so that it has a "Home_Control" template with legit values for its fields? Would that even be the right approach? Most online sources I've found do not have a similar scenario, I'm looking for the shortest code possible.

Another question I had is, how can I test the below Index() method in my [TestMethod], given that the SitecoreContext is declared inside the Index() method, rather than received in the HomeBottomContentController constructor like above? Is there a way to do that from the [TestMethod], or we have to send in the SitecoreContext into the HomeBottomContentController constructor or into the Index() method as a parameter?

public override ActionResult Index()
{
    var context = new SitecoreContext();
    var model = context.GetCurrentItem<Home_Control>();
    return View("~/Views/HomeBottomContent/HomeBottomContent.cshtml", model);
}

In that case you would need to mock the desired behavior on the mocked dependency

[TestClass]
public class UnitTest1 {
    [TestMethod]
    public void Test_ISitecoreContextInsertion() {
        //Arrange
        var model = new Home_Control() {
            //...populate as needed
        }
        var iSitecoreContext = new Mock<Glass.Mapper.Sc.ISitecoreContext>();
        //Setup the method to return a model when called.
        iSitecoreContext.Setup(_ => _.GetCurrentItem<Home_Control>()).Returns(model);
        var controllerUnderTest = new HomeBottomContentController(iSitecoreContext.Object);

        //Act
        var result = controllerUnderTest.Index() as ViewResult;

        //Assert
        Assert.IsNotNull(result);
        Assert.IsNotNull(result.Model);
        //...other assertions.
    }
}

UPDATE

Creating the context within the action tightly couples it to the context, making it almost impossible to mock. That is the reason explicit dependencies are injected

You can do something like that:

public class HomeBottomContentController : GlassController
{
    private readonly ISitecoreContext _iSitecoreContext;
    public HomeBottomContentController(ISitecoreContext iSitecoreContext)
    {
        _iSitecoreContext = iSitecoreContext;
    }

    public override ActionResult Index()
    {
        var model = this.GetCurrentItem();
        return View("~/Views/HomeBottomContent/HomeBottomContent.cshtml", model);
    }

    protected virtual Home_Control GetCurrentItem() 
    {
        return _iSitecoreContext.GetCurrentItem<Home_Control>();
    }
}

namespace WTW.Feature.HomeBottomContent.Tests
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void Test_ISitecoreContextInsertion()
        {       
            var iSitecoreContext = Mock.Of<Glass.Mapper.Sc.ISitecoreContext>();
            var controllerUnderTest = new FakeHomeBottomContentController(iSitecoreContext);
            var result = controllerUnderTest.Index() as ViewResult;
            Assert.IsNotNull(result);
        }
    }

    public class FakeHomeBottomContentController : HomeBottomContentController 
    {
        public FakeHomeBottomContentController(ISitecoreContext iSitecoreContext) : base(iSitecoreContext) 
        {
        }

        protected override Home_Control GetCurrentItem()
        {
            // return instance of Home_Control type
            // e.g.         
            return new Home_Control();
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM