我是sitecore开发人员,我想创建一个示例sitecore螺旋单元测试项目,用于测试您在“EmailArticleController”控制器的Index()操作方法中看到的逻辑:
using Sitecore.Mvc.Presentation;
public class EmailArticleController : GlassController
{
//logic in below Index() method is what I want to test
public override ActionResult Index()
{
var _emailArticleBusiness = new EmailArticleBusiness();
var model = _emailArticleBusiness.FetchPopulatedModel;
var datasourceId = RenderingContext.Current.Rendering.DataSource;
_emailArticleBusiness.SetDataSourceID(datasourceId);
return View("~/Views/EmailCampaign/EmailArticle.cshtml", model);
}
//below is alternative code I wrote for mocking and unit testing the logic in above Index() function
private readonly IEmailArticleBusiness _businessLogic;
private readonly RenderingContext _renderingContext;
public EmailArticleController(IEmailArticleBusiness businessLogic, RenderingContext renderingContext)
{
_businessLogic = businessLogic;
_renderingContext = renderingContext;
}
public ActionResult Index(int forUnitTesting)
{
var model = _businessLogic.FetchPopulatedModel;
// *** do below two lines of logic somehow go into my Unit Testing class? How?
var datasourceId = _renderingContext.Rendering.DataSource;
_businessLogic.SetDataSourceID(datasourceId);
// ***
return View("~/Views/EmailCampaign/EmailArticle.cshtml", model);
}
}
好的,这就是我在单元测试课中所拥有的:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void Test_EmailArticleController_With_RenderingContext()
{
//Arrange
var businessLogicFake = new Mock<IEmailArticleBusiness>();
var model = new EmailArticleViewModel()
{
ArticleControl = new Article_Control() { },
Metadata = new Metadata() { }
};
businessLogicFake.Setup(x => x.FetchPopulatedModel).Returns(model);
// I'm not sure about the next 3 lines, how do I mock the RenderingContext and send it into the constructor, given that it needs a DataSource value too?
var renderingContext = Mock.Of<Sitecore.Mvc.Presentation.RenderingContext>( /*what goes here, if anything?*/ ) { /*what goes here, if anything?*/ };
EmailArticleController controllerUnderTest = new EmailArticleController(businessLogicFake.Object, renderingContext);
var result = controllerUnderTest.Index(3) as ViewResult;
Assert.IsNotNull(result);
}
}
基本上我想模拟一个渲染上下文,确保它有一个(字符串)DataSource值设置为某个值,例如“/ sitecore / home / ...”,我想将它发送到控制器的构造函数中(如果这是正确的方法),调用Index(int)方法,同时确保我的_businessLogic,在这种情况下只是一个接口(应该是具体的类吗?)将其dataSource设置为相同的值在返回视图之前。
完成所有这些操作的确切代码是什么?谢谢!
答案 0 :(得分:1)
将代码紧密耦合到RenderingContext.Current.Rendering.DataSource
之类的静态依赖项可能会使代码的测试变得困难。
我建议您创建一个封装器来封装对RenderingContext
的静态访问。参考在GitHub上的Glass.Mapper存储库中找到的代码示例
public interface IRenderingContext {
string GetDataSource();
}
//...
using Sitecore.Mvc.Presentation;
public class RenderingContextWrapper : IRenderingContext {
public string GetDataSource(){
return RenderingContext.CurrentOrNull.Rendering.DataSource;
}
}
然后,您将更新控制器,以通过构造函数注入显式依赖于该抽象
public class EmailArticleController : GlassController {
private readonly IEmailArticleBusiness businessLogic;
private readonly IRenderingContext renderingContext;
public EmailArticleController(IEmailArticleBusiness businessLogic, IRenderingContext renderingContext) {
this.businessLogic = businessLogic;
this.renderingContext = renderingContext;
}
public ActionResult Index() {
var model = businessLogic.FetchPopulatedModel;
var datasourceId = renderingContext.GetDataSource();
businessLogic.SetDataSourceID(datasourceId);
return View("~/Views/EmailCampaign/EmailArticle.cshtml", model);
}
}
您现在可以模拟所有依赖项,以便能够单独测试控制器。
[TestClass]
public class UnitTest1 {
[TestMethod]
public void Test_EmailArticleController_With_RenderingContext() {
//Arrange
var businessLogicFake = new Mock<IEmailArticleBusiness>();
var model = new EmailArticleViewModel() {
ArticleControl = new Article_Control() { },
Metadata = new Metadata() { }
};
businessLogicFake.Setup(x => x.FetchPopulatedModel).Returns(model);
var datasourceId = "fake_datasourceId";
var renderingContext = Mock.Of<IRenderingContext>(_ => _.GetDataSource() == datasourceId);
var controllerUnderTest = new EmailArticleController(businessLogicFake.Object, renderingContext);
//Act
var result = controllerUnderTest.Index() as ViewResult;
//Assert
Assert.IsNotNull(result);
businessLogicFake.Verify(_ => _.SetDataSourceID(datasourceId), Times.AtLeastOnce());
}
}
您的生产代码显然会使用您的DI容器注册抽象和实现,以便运行时解析依赖项。