如何对 Sitecore MVC 中的方法进行单元测试,该方法对两个不同的 Sitecore 上下文具有紧密耦合的依赖性?

How to Unit Test a Method in Sitecore MVC having tightly coupled Dependency on two distinct Sitecore Contexts?

不幸的是,我不得不为遗留的 Sitecore MVC 代码库编写单元测试,其中调用了两个不同的 Sitecore 上下文。我知道这属于集成测试,但我没有选择在这方面教育我的项目负责人。所以我选择使用 FakeDb 来模拟 Sitecore 实例和 NSubstitute 来替换注入的依赖项(不能使用任何 Profilier API 框架由于预算限制,例如 MS Fakes、TypeMock 等)。我提供以下代码:

要进行单元测试的方法

 public bool DubiousMethod()
 {
    // This HttpContext call is pain area 1. This gets resolved when i call it using ItemContextSwitcher in Unit Tests.
    string currentUrl = HttpContext.Current.Request.RawUrl; 

   // This Sitecore Context call to Site Name is pain area 2. This gets resolved when Unit Tests are run under SiteContextSwitcher.
    string siteName = Sitecore.Context.Site.Name;

    return true/False;
 }

单元测试方法

[Fact]

public void DubiousMethodUT()
{
 // create a fake site context            
        var fakeSite = new Sitecore.FakeDb.Sites.FakeSiteContext(
          new Sitecore.Collections.StringDictionary
           {
              { "name", "website" }, { "database", "web" }, { "rootPath", "/sitecore/content/home" },
              { "contentStartItem", "home"}, {"hostName","https://www.myorignalsiteurl.com"}                 

           });

 using (new Sitecore.Sites.SiteContextSwitcher(fakeSite))
        {                           
            //DubiousClassObject.DubiousMethod(home) // When Debugging after uncommenting this line i get correct value in **Sitecore.Context.Site.Name**
            using (Sitecore.FakeDb.Db db = new Sitecore.FakeDb.Db
                 {

                   new Sitecore.FakeDb.DbItem("home") { { "Title", "Welcome!" } ,

                   new Sitecore.FakeDb.DbItem("blogs") }
                  })

            {

                Sitecore.Data.Items.Item home = db.GetItem("/sitecore/content/home");
                //bool abc = confBlogUT.IsBlogItem(home);
                using (new ContextItemSwitcher(home))
                {
                    string siteName = Sitecore.Context.Site.Name;
                    var urlOptions = new Sitecore.Links.UrlOptions();
                    urlOptions.AlwaysIncludeServerUrl = true;
                    var pageUrl = Sitecore.Links.LinkManager.GetItemUrl(Sitecore.Context.Item, urlOptions);
                    HttpContext.Current = new HttpContext(new HttpRequest("", pageUrl.Substring(3), ""), new HttpResponse(new StringWriter()));



                    Assert.False(DubiousClassObject.DubiousMethod(home); //When Debugging after commenting above DubiousMethodCall i get correct value for **HttpContext.Current.Request.RawUrl**
                }
            }
        }
    }

如您所见,当我尝试从 FakSiteContext 调用该方法时,我得到了 Sitecore.Context.Site.Name 的正确值,但是当 HttpContext.Current.Request.RawUrl 在方法中被调用。当我从 ContextItemSwitcher(FakeItem) 上下文调用方法时,情况正好相反。到目前为止,我还没有找到合并两个上下文的方法(我认为这在 Sitecore 中是不可能的)。任何人都可以建议我 运行 我在总体上下文中进行单元测试,我能够控制 fakeSite 变量以及 FakeItem 上下文变量以及扩展任何其他 Sitecore 上下文调用吗?

如有任何帮助,我们将不胜感激。

我建议您看一下 Unit testing in Sitecore 文章,因为它似乎正是您所需要的。

简而言之 - 您需要对代码进行一些调整以使其可测试:

1) 将 static HttpContext 替换为抽象 HttpContextBase (impl. HttpContextWrapper) 以便可以安排所有内容 - DubiousMethod 获得接受 [=14 的重载=].

2) 至于 Sitecore 上下文数据 - 它具有 Sitecore.Caching.ItemsContext 绑定语义(如文章中所述),因此您可以在每次测试时清理集合 before/after 以获得某种隔离测试之间。

或者,您可以为 Sitecore.Context 烘焙一个类似的包装器,就像 ASP.NET 团队为 HttpContext -> HttpContextBase 和 impl HttpContextWrapper.