如何unit testing使用Sitecore.Context.Item的GlassController动作

我是sitecore开发人员,我想创建一个示例sitecore螺旋unit testing项目,用于测试您在“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); } } 

这是我在unit testing课中的内容:

 [TestClass] public class UnitTest1 { [TestMethod] public void Test_ArticleController_With_SitecoreItem() { //Arrange var businessLogicFake = new Mock(); 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”),以某种方式将它发送到控制器,并执行与大if语句相同的逻辑在我们原来的“公共覆盖ActionResult Index()”方法中。

完成所有这些的确切代码是什么? 谢谢!

我强烈建议您使用Sitecore.FakeDb作为Sitecore的unit testing框架。 简而言之,上下文项目的模拟将如下所示:

 [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}"); } } 

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

封装您控制的抽象背后的所需function。

 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或任何其他框架单独模拟依赖项,以进行unit testing。