我正在开发一个通过Sitecore CMS构建的Web应用程序。我想知道我们是否可以进行单元测试,例如从Sitecore获取一些数据的方法对其进行一些处理并吐出结果。我想通过单元测试来测试方法中的所有逻辑。
在互联网上搜索后,我非常困惑。有人说这种测试实际上是集成测试而不是单元测试,我应该只测试没有Sitecore调用的代码,其他人说这是不可能的,因为Sitecore上下文会丢失。我想请求你的经验丰富的同事们: 我可以单元测试包含Sitecore调用的方法吗?如果是,怎么样?如果不是,为什么?有没有解决方法?
该项目刚刚开始,因此在选择MSTest或Nunit等单元测试框架时,如果解决方案与所选的单元测试框架相关,则没有问题。
答案 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。但是,从您的问题来看,它似乎是您的应用程序外部的东西。应始终通过接口使用系统外部的组件。这有两个好处:
您编写的代码是您的责任,因此您只应对该段代码进行单元测试。您的单元测试应确保您的代码在各种场景(行为测试)中调用适当的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的站点