我可以对进行 Sitecore 上下文调用的方法进行单元测试吗?

发布于 2024-09-09 07:07:43 字数 379 浏览 7 评论 0原文

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

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

恳请各位有经验的程序员帮忙: 我可以对包含 Sitecore 调用的方法进行单元测试吗?如果是,怎么办?如果否,为什么?有什么解决方法吗?

由于项目还处于起步阶段,因此如果解决方案与所选的单元测试框架相关,那么在 MSTest 或 Nunit 等单元测试框架之间进行选择是没有问题的。

I'm working on a web application that is built over Sitecore CMS. I was wondering if we could unit test for example a method that takes some data from Sitecore makes some processing with it and spits out a result. I would like to test all the logic within the method via a unit test.

I pretty confused after searching the internet wide and deep. Some say that this kind of testing is actually integration testing and not unit testing and I should test only the code that has no Sitecore calls, others say that this is not possible because the Sitecore context would be missing.

I would like to ask for your help experienced fellow programmers:
Can I unit test a method that contains Sitecore calls ? If YES, how ? If NO, why ? Is there any workaround ?

The project is at its beginning, so there will be no problem in choosing between unit testing frameworks such as MSTest or Nunit, if it is the case that the solution is related to the unit testing framework of choice.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

绅刃 2024-09-16 07:07:43

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

首先也是最重要的,您假设 Sitecore API 保证工作 - 即它是一个框架 - 并且您不对它进行单元测试。您应该对与它的交互进行单元测试。

然后,下载最小起订量并阅读快速入门。这是我首选的模拟框架。如果您愿意,可以随意使用其他框架。

希望 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 模式 包装 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 的所有交互。

It's pretty hard to find out anything about Sitecore without providing email and living through the sales pitch, so I'll just provide a generic approach on how to do something like this.

First and foremost, you assume that the Sitecore API is guaranteed to work - i.e. it's a framework - and you don't unit test it. You should be unit testing your interactions with it.

Then, download MOQ and read the quick start on how to use it. This is my preferred mocking framework. Feel free to use other frameworks if you wish.

Hopefully, Sitecore API provides a way for you to create data objects without dealing with persistence - i.e. to simply create a new instance of whatever it is you are interested in. Here is my imaginary 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);
}

In this case unit testing should be fairly easy. With a bit of Dependency Injection, you can inject the SiteCore interfaces into your component and then unit test it.

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();
  }
}

If ISiteCorePosts is not, in fact, an interface and is a concrete class whose methods are not virtual and thus cannot be mocked, you will need to use Facade pattern to wrap the SiteCore interaction to make it more testing friendly.

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

You then proceed to use SiteCorePostsFacade as though it was an interface in the previous example. Good thing about MOQ is that it allows you to mock concrete classes with virtual methods, not just interfaces.

With this approach, you should be able to inject all sorts of data into your application to test all interactions with SiteCore API.

明天过后 2024-09-16 07:07:43

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

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

测试愉快!

we have used a custom WebControl placed on a WebForm for our integration tests some years now, which wraps the NUnit Test Suite runner functionality much like the NUnit GUI. It show a pretty grid of executed tests with links to fixtures and categories to execute specific tests. Its created much like described here http://adeneys.wordpress.com/2010/04/13/new-technique-for-unit-testing-renderings-in-sitecore/ (the custom test runner part). Our implementation can also return raw NUnit xml for further processing by for example a build server.

I've tried MSTest a while back and it also works when specified that it should launch a WebDev / IIS site to test. It works but is extremely slow compared to above solution.

Happy testing!

面如桃花 2024-09-16 07:07:43

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

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

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

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

Short answer:
You need to mock calls to SiteCore CMS.

Long answer:
I am not aware about SiteCore CMS. But, from your question looks like it is something that is external to your application. Components external to your system should always be used via interface. This has two benefits:

  1. If you want to use another CMS system, you can easily do as your application is just talking to an interface.
  2. It helps you with behavior testing by mocking the interface.

The code you write is your responsibility and hence you should only unit test that piece of code. Your unit tests should ensure that your code calls appropriate SiteCode CMS methods in various scenarios (behavior tests). You can do this using mocking. I use moq for mocking.

千纸鹤带着心事 2024-09-16 07:07:43

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

SomeSiteCoreService siteCoreDependency = new SomeSiteCoreService()

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

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

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

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

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

As tugga said, it depends upon how tightly the code you want to test is coupled to SiteCore. If it's something like:

SomeSiteCoreService siteCoreDependency = new SomeSiteCoreService()

Then this would be very difficult to test. If SiteCore provides you an interface, then you have more flexibility to unit test it. You could pass the implementation into your method either (contstructor, class property, or method parameter) and then you can send in a fake implementation of that service.

If they do not provide you with an interface, then you have to do a little more work. You would write an adapter interface of your own and the default implementation would delegate to the 3rd party dependency.

public interface ICMSAdapter{
void DoSomethingWithCMS()
}

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

That keeps your 3rd party dependencies at arms length and provides seams to all sorts of cool things, like unit tests and you do interception style architecture and do your own thing before and after the call.
}

醉梦枕江山 2024-09-16 07:07:43

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

例如,此方法调用在 VS2015 中运行良好,但在 VS2015 中运行不佳:

Context.SetActiveSite("mysite");

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

I was able to get unit tests to interact with sitecore api in VS 2015. The same test throws a StackOverflow exception when run in VS 2012.

For example, this method call runs fine in VS2015 but not VS2015:

Context.SetActiveSite("mysite");

quick note: this assumes you have a site named mysite setup in your config file

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文