我可以单元测试一个使Sitecore上下文调用的方法吗?

时间:2010-07-12 19:11:57

标签: unit-testing nunit mstest sitecore sitecore6

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

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

我想请求你的经验丰富的同事们: 我可以单元测试包含Sitecore调用的方法吗?如果是,怎么样?如果不是,为什么?有没有解决方法?

该项目刚刚开始,因此在选择MSTest或Nunit等单元测试框架时,如果解决方案与所选的单元测试框架相关,则没有问题。

5 个答案:

答案 0 :(得分:2)

很难在没有提供电子邮件和生活销售宣传的情况下找到关于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的所有交互。

答案 1 :(得分:1)

我们已经使用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站点进行测试时也能正常工作。它可以工作,但与上述解决方案相比速度极慢。

快乐测试!

答案 2 :(得分:1)

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

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

  1. 如果您想使用其他CMS系统,您可以轻松完成,因为您的应用程序只是在与界面交谈。
  2. 它通过模拟界面帮助您进行行为测试。
  3. 您编写的代码是您的责任,因此您只应对该段代码进行单元测试。您的单元测试应确保您的代码在各种场景(行为测试)中调用适当的SiteCode CMS方法。你可以使用模拟来做到这一点。我使用moq进行嘲弄。

答案 3 :(得分:0)

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

SomeSiteCoreService siteCoreDependency = new SomeSiteCoreService()

然后这将是非常难以测试的。如果SiteCore为您提供了界面,那么您可以更灵活地对其进行单元测试。您可以将实现传递给您的方法(contstructor,class属性或方法参数),然后您可以发送该服务的虚假实现。

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

public interface ICMSAdapter {    void DoSomethingWithCMS()
}

public class SiteCoreCMSAdapter:ICMSAdapter {   SiteCoreService _cms = new SiteCoreService();   public void DoSomethingWithCMS(){     _cms.DoSomething();   }

这可以保持你的第三方依赖关系,并为各种很酷的事情提供接缝,比如单元测试,你可以做拦截风格的架构,并在通话前后做自己的事情。 }

答案 4 :(得分:0)

我能够在VS 2015中使用单元测试与sitecore api进行交互。在VS 2012中运行时,同一测试会抛出StackOverflow异常。

例如,此方法调用在VS2015中运行正常,但在VS2015中运行不正确:

Context.SetActiveSite("mysite");

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