【问题标题】:How to Unit Test a GlassController Action which Uses Sitecore.Context.Item如何对使用 Sitecore.Context.Item 的 GlassController 动作进行单元测试
【发布时间】:2018-02-25 02:23:28
【问题描述】:

我是一名 sitecore 开发人员,我想创建一个示例 sitecore helix 单元测试项目,用于测试您在我们的“ArticleController”控制器的 Index() 操作方法中看到的逻辑:

public class ArticleController : GlassController
{
    public override ActionResult Index()
    {
        // If a redirect has been configured for this Article, then redirect to new location.
        if (Sitecore.Context.Item.Fields[SitecoreFieldIds.WTW_REDIRECT_TO] != null && !string.IsNullOrEmpty(Sitecore.Context.Item.Fields[SitecoreFieldIds.WTW_REDIRECT_TO].Value))
        {
            var link = (LinkField)Sitecore.Context.Item.Fields[SitecoreFieldIds.WTW_REDIRECT_TO];
            if (link != null)
            {
                if (link.IsInternal)
                {
                    return Redirect(Sitecore.Links.LinkManager.GetItemUrl(link.TargetItem));
                }
                else
                {
                    return Redirect(link.Url);
                }
            }
        }

        var model = new ArticleBusiness().FetchPopulatedModel;

        return View("~/Views/Article/Article.cshtml", model);
    }

    //below is alternative code I wrote for mocking and unit testing the logic in above Index() function
    private readonly IArticleBusiness _businessLogic;
    public ArticleController(IArticleBusiness businessLogic)
    {
        _businessLogic = businessLogic;
    }
    public ActionResult Index(int try_businessLogic)
    {
        // How do we replicate the logic in the big if-statement in above "override ActionResult Index()" method?

        var model = _businessLogic.FetchPopulatedModel;

        return View("~/Views/EmailCampaign/EmailArticle.cshtml", model);
    }
}

这是我在单元测试课上的内容:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void Test_ArticleController_With_SitecoreItem()
    {
        //Arrange
        var businessLogicFake = new Mock<IArticleBusiness>();

        var model = new ArticleViewModel()
        {
            ArticleType = "Newsletter",
            ShowDownloadButton = true
        };

        businessLogicFake.Setup(x => x.FetchPopulatedModel).Returns(model);
        //How do I also mock the Sitecore.Context.Item and send it into the constructor, if that's the right approach?

        ArticleController controllerUnderTest = new ArticleController(businessLogicFake.Object);

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

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

基本上我想模拟一个 Sitecore.Context.Item,它有一个“LinkField”值(上面称为“SitecoreFieldIds.WTW_REDIRECT_TO”),以某种方式将它发送到控制器,并执行与大的相同的确切逻辑我们最初的“public override ActionResult Index()”方法中的 if 语句。

执行所有这些操作的确切代码是什么?谢谢!

【问题讨论】:

    标签: c# moq sitecore8 sitecore-mvc glass-mapper


    【解决方案1】:

    您将代码/逻辑与静态类耦合,这使得单独测试变得困难。您还试图模拟您无法控制的代码。

    在您控制的抽象背后封装所需的功能。

    public interface IArticleRedirectService {
        Url CheckUrl();
    }
    
    public class ArticleRedirectionService : IArticleRedirectionService {
        public Url CheckUrl() {            
            if (Sitecore.Context.Item.Fields[SitecoreFieldIds.WTW_REDIRECT_TO] != null && 
                !string.IsNullOrEmpty(Sitecore.Context.Item.Fields[SitecoreFieldIds.WTW_REDIRECT_TO].Value)) {
                var link = (LinkField)Sitecore.Context.Item.Fields[SitecoreFieldIds.WTW_REDIRECT_TO];
                if (link != null) {
                    if (link.IsInternal) {
                        return Sitecore.Links.LinkManager.GetItemUrl(link.TargetItem);
                    } else {
                        return link.Url;
                    }
                }
            }
            return null;
        }
    }
    

    控制器将通过构造函数注入显式依赖服务。

    public class ArticleController : GlassController {            
        private readonly IArticleBusiness businessLogic;
        private readonly IArticleRedirectionService redirect;
    
        public ArticleController(IArticleBusiness businessLogic, IArticleRedirectionService redirect) {
            this.businessLogic = businessLogic;
            this.redirect = redirect;
        }
    
        public ActionResult Index() {
            // If a redirect has been configured for this Article, 
            // then redirect to new location.
            var url = redirect.CheckUrl();
            if(url != null) {
                return Redirect(url);
            }
            var model = businessLogic.FetchPopulatedModel;    
            return View("~/Views/EmailCampaign/EmailArticle.cshtml", model);
        }
    }
    

    代码现在可以灵活地独立模拟依赖项,以便使用 Moq 或任何其他框架进行单元测试。

    【讨论】:

      【解决方案2】:

      我强烈建议您将Sitecore.FakeDb 用于此目的,它是 Sitecore 的单元测试框架。所以简而言之,对上下文项目的模拟将如下所示:

      [TestCase]
      public void FooActionResultTest()
      {
          // arrange
          var itemId = ID.NewID;
          using (var db = new Db
          {
              new DbItem("Some Item", itemId)
              {
                  new DbField(SitecoreFieldIds.WTW_REDIRECT_TO) { Value = "{some-raw-value}" }
              }
          })
          {   
              // act  
              Sitecore.Context.Item = db.GetItem(itemId);
      
              // assert
              Sitecore.Context.Item[SitecoreFieldIds.WTW_REDIRECT_TO].Should().Be("{some-raw-value}");
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-04-02
        • 1970-01-01
        • 2012-01-08
        • 2017-05-28
        • 2013-04-16
        • 2016-05-29
        • 2017-10-04
        相关资源
        最近更新 更多