【问题标题】:Can I unit test a method that makes Sitecore context calls?我可以对进行 Sitecore 上下文调用的方法进行单元测试吗?
【发布时间】:2010-07-12 19:11:57
【问题描述】:

我正在开发基于 Sitecore CMS 构建的 Web 应用程序。我想知道我们是否可以进行单元测试,例如从 Sitecore 获取一些数据的方法对其进行一些处理并输出结果。我想通过单元测试来测试方法中的所有逻辑。

在广泛深入地搜索互联网后,我感到很困惑。有人说这种测试实际上是集成测试而不是单元测试,我应该只测试没有 Sitecore 调用的代码,其他人说这是不可能的,因为 Sitecore 上下文会丢失。

我想向有经验的程序员寻求帮助: 我可以对包含 Sitecore 调用的方法进行单元测试吗?如果是,如何?如果否,为什么?有什么解决办法吗?

项目刚开始,所以如果解决方案与选择的单元测试框架有关,那么在MSTest或Nunit等单元测试框架之间进行选择是没有问题的。

【问题讨论】:

  • 我能够在 VS 2015 中进行单元测试以与 sitecore api 进行交互。

标签: unit-testing nunit mstest sitecore sitecore6


【解决方案1】:

如果不提供电子邮件并通过销售宣传,很难找到有关 Sitecore 的任何信息,因此我将提供一个通用方法来说明如何执行此类操作。

首先,您假设 Sitecore API 可以保证工作 - 即它是一个框架 - 而您不进行单元测试。您应该对与它的交互进行单元测试。

然后,download MOQ 并阅读 quick start on how to use it。这是我首选的模拟框架。如果您愿意,请随意使用其他框架。

希望 Sitecore API 为您提供了一种无需处理持久性即可创建数据对象的方法 - 即简单地为您感兴趣的任何内容创建一个新实例。这是我想象中的 API:

public class Post {
  public string Body {get;set;}
  public DateTime LastModified {get;set;}
  public string Title {get;set;}
}

public interface ISiteCorePosts {
  public IEnumerable<Post> GetPostsByUser(int userId);
}

在这种情况下,单元测试应该相当容易。通过一点依赖注入,您可以将 SiteCore 接口注入到您的组件中,然后对其进行单元测试。

public class MyPostProcessor {

  private readonly ISiteCorePosts m_postRepository;

  public MyPostProcessor(ISiteCorePosts postRepository) {
    m_postRepository = postRepository;
  }

  public void ProcessPosts(int userId) {
     var posts = m_postRepository.GetPostsByUser(userId);
     //do something with posts
  }
}

public class MyPostProcessorTest {
  [TestMethod]
  ProcessPostsShouldCallGetPostsByUser() {
    var siteCorePostsMock = new Mock<ISiteCorePosts>();
    //Sets up the mock to return a list of posts when called with userId = 5
    siteCorePostsMock.Setup(m=>m.GetPostsByUser(5)).Returns(new List<Post>{/*fake posts*/});

    MyPostProcessor target = new MyPostProcessor(siteCorePostsMock.Object);
    target.ProcessPosts(5);
    //Verifies that all setups are called
    siteCorePostsMock.VerifyAll();
  }
}

如果ISiteCorePosts 实际上不是一个接口并且是一个具体的类,其方法不是虚拟的,因此不能被模拟,你将需要使用Facade pattern 来包装SiteCore 交互,使其对测试更加友好.

public class SiteCorePostsFacade {

  SiteCorePosts m_Posts = new SiteCorePosts();

  //important - make this method virtual so it can be mocked without needing an interface
  public virtual IEnumerable<Post> GetPostsByUser(int userId) {
    return m_Posts.GetPostsByUser(userId);
  }
}

然后您继续使用SiteCorePostsFacade,就好像它是前面示例中的接口一样。 MOQ 的好处是它允许您使用虚拟方法模拟具体类,而不仅仅是接口。

使用这种方法,您应该能够将各种数据注入您的应用程序,以测试与 SiteCore API 的所有交互。

【讨论】:

  • 好的,我了解您的解决方案的逻辑流程。但是,如果我不想模拟 Sitecore 交互怎么办?可以进行“单元测试”吗?我引用单元测试是因为这更像是一种集成测试方法,对吗?我想测试我的代码与真实的 Sitecore 服务调用集成。
  • 根据定义,当您进行单元测试时,您测试的是小单元代码。因此,您只想验证 编写的代码是否有意义,而不是其他人编写的代码。这就是模拟的用武之地,它允许您隔离组件并专注于非常小的代码块。这个答案是对组件进行单元测试的经典示例。单元测试通常意味着模拟。集成测试是您可以使用真实 API 的地方,但它要困难得多,并且通常会涉及在测试之前处于已知状态并在测试之后处于预期状态的数据库。
【解决方案2】:

几年来,我们已经使用放置在 WebForm 上的自定义 WebControl 来进行集成测试,它封装了 NUnit Test Suite 运行器功能,非常类似于 NUnit GUI。它显示了一个漂亮的已执行测试网格,其中包含指向夹具和类别的链接以执行特定测试。它的创建很像这里描述的http://adeneys.wordpress.com/2010/04/13/new-technique-for-unit-testing-renderings-in-sitecore/(自定义测试运行器部分)。我们的实现还可以返回原始 NUnit xml 以供构建服务器等进一步处理。

我已经尝试过 MSTest 一段时间,当指定它应该启动 WebDev / IIS 站点进行测试时它也可以工作。它可以工作,但与上述解决方案相比非常慢。

测试愉快!

【讨论】:

    【解决方案3】:

    简答: 您需要模拟对 SiteCore CMS 的调用。

    长答案: 我不知道 SiteCore CMS。但是,从您的问题看来,它是您的应用程序外部的东西。系统外部的组件应始终通过接口使用。这有两个好处:

    1. 如果您想使用另一个 CMS 系统,您可以轻松地做到这一点,因为您的应用程序只是与一个界面对话。
    2. 它通过模拟界面帮助您进行行为测试。

    您编写的代码是您的责任,因此您应该只对那段代码进行单元测试。您的单元测试应确保您的代码在各种场景(行为测试)中调用适当的 SiteCode CMS 方法。您可以使用模拟来做到这一点。我使用 moq 进行模拟。

    【讨论】:

      【解决方案4】:

      正如 tugga 所说,这取决于您要测试的代码与 SiteCore 耦合的紧密程度。如果是这样的:

      SomeSiteCoreService siteCoreDependency = new SomeSiteCoreService()
      

      那么这将很难测试。如果 SiteCore 为您提供接口,那么您可以更灵活地对其进行单元测试。您可以将实现传递给您的方法(构造函数、类属性或方法参数),然后您可以发送该服务的假实现。

      如果他们没有为您提供界面,那么您必须做更多的工作。您将编写自己的适配器接口,默认实现将委托给第 3 方依赖项。

      公共接口 ICMSAdapter{ 无效 DoSomethingWithCMS()
      }

      公共类 SiteCoreCMSAdapter: ICMSAdapter{ SiteCoreService _cms = new SiteCoreService(); 公共无效 DoSomethingWithCMS(){ _cms.DoSomething(); }

      这使您的第 3 方依赖关系保持一定距离,并为各种很酷的事情提供接缝,例如单元测试,您可以进行拦截式架构并在调用前后做自己的事情。 }

      【讨论】:

        【解决方案5】:

        我能够在 VS 2015 中进行单元测试以与 sitecore api 交互。在 VS 2012 中运行时,相同的测试会引发 StackOverflow 异常。

        例如,这个方法调用在 VS2015 中运行良好,但在 VS2015 中就不行:

        Context.SetActiveSite("mysite");
        

        快速说明:假设您的配置文件中有一个名为 mysite setup 的站点

        【讨论】:

          猜你喜欢
          • 2010-09-22
          • 1970-01-01
          • 2011-07-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多