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

Unit testing 如何在Sitecore MVC中对一个方法进行单元测试,该方法对两个不同的Sitecore上下文具有紧密耦合的依赖关系?,unit-testing,model-view-controller,mocking,sitecore-mvc,sitecore9,Unit Testing,Model View Controller,Mocking,Sitecore Mvc,Sitecore9,不幸的是,我不得不为一个遗留的Sitecore MVC代码库编写单元测试,其中调用了两个不同的Sitecore上下文。我知道这需要进行集成测试,但我没有选择在这方面教育我的项目负责人。因此,我选择使用FakeDb来模拟Sitecore实例,并使用NSubstitute来替换注入的依赖项(由于预算限制,无法使用任何更有利的API框架,如MS Fakes、TypeMock等)。我提供以下代码: 要进行单元测试的方法 public bool DubiousMethod() { // Thi

不幸的是,我不得不为一个遗留的Sitecore MVC代码库编写单元测试,其中调用了两个不同的Sitecore上下文。我知道这需要进行集成测试,但我没有选择在这方面教育我的项目负责人。因此,我选择使用FakeDb来模拟Sitecore实例,并使用NSubstitute来替换注入的依赖项(由于预算限制,无法使用任何更有利的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**
                }
            }
        }
    }
单元测试方法

 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上下文调用


任何帮助都将不胜感激。

我建议您看看这篇文章,因为它似乎正是您所需要的

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

1) 将静态的
HttpContext
替换为抽象的
HttpContextBase
(impl.
HttpContextWrapper
),这样一切都可以安排-
DubiousMethod
获取一个重载,该重载接受
DubiousMethod(HttpContextBase HttpContext)

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

或者,您也可以像ASP.NET团队为
HttpContext
->
HttpContextBase
&impl
HttpContextWrapper
所做的那样,为Sitecore.Context烘焙一个类似的包装