所以我正在使用Umbraco 6.12并且很难测试RenderMvcController
。
我已经在我的IApplicationEventHandler
中实现了Global.ascx
,并且Ninject工作正常,正如预期的那样运行应用程序时 - 一切都很好。
然而,对这些控制器进行单元测试是另一回事。我发现了这个,并添加了最新的回复:
http://issues.umbraco.org/issue/U4-1717
我现在在我的SetUp中有这个可爱的黑客:
Umbraco.Web.UmbracoContext.EnsureContext(new HttpContextWrapper(new HttpContext(new HttpRequest("", "http://www.myserver.com", ""), new HttpResponse(null))), ApplicationContext.Current);
原来的UmbracoContext
附近不能为空,但现在抛出:
当前尚未在Umbraco.Web.PublishedCache.PublishedCachesResolver上初始化。您必须在尝试读取之前初始化Current。
已发布的缓存解析器似乎也隐藏在内部和受保护的内容之后,我无法使用反射来破解,因为我无法初始化SetProperty
反射。
真的很令人沮丧,我喜欢v6,使用uMapper非常好。我可以随意将一个回购,服务,命令或查询注入控制器,生活很美好 - 我无法覆盖控制器!
对此的任何帮助将不胜感激。
感谢。
答案 0 :(得分:10)
要对Umbraco RenderMvcController进行单元测试,您需要grab the source code from github,自己编译解决方案,并获取Umbraco.Tests.dll并在测试项目中引用它。
除此之外,您还需要引用随Umbraco软件包一起分发的SQLCE4Umbraco.dll和内部用于模拟的Rhino.Mocks.dll。
为了帮助你,我已经编译了Umbraco.Tests.dll用于Umbraco 6.1.5并将它与Rhino.Mocks.dll一起放在this zip file上。
最后,从BaseRoutingTest派生您的测试,覆盖DatabaseTestBehavior NoDatabasePerFixture,通过调用GetRoutingContext方法获取UmbracoContext和HttpBaseContext,如下面的代码所示:
using System;
using Moq;
using NUnit.Framework;
using System.Globalization;
using System.Web.Mvc;
using System.Web.Routing;
using Umbraco.Core.Models;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
namespace UnitTests.Controllers
{
public class Entry
{
public int Id { get; set; }
public string Url { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
public string Content { get; set; }
public string Author { get; set; }
public string[] Tags { get; set; }
public DateTime Date { get; set; }
}
public interface IBlogService
{
Entry GetBlogEntry(int id);
}
public class BlogEntryController : RenderMvcController
{
private readonly IBlogService _blogService;
public BlogEntryController(IBlogService blogService, UmbracoContext ctx)
: base(ctx)
{
_blogService = blogService;
}
public BlogEntryController(IBlogService blogService)
: this(blogService, UmbracoContext.Current)
{
}
public override ActionResult Index(RenderModel model)
{
var entry = _blogService.GetBlogEntry(model.Content.Id);
// Test will fail if we return CurrentTemplate(model) as is expecting
// the action from ControllerContext.RouteData.Values["action"]
return View("BlogEntry", entry);
}
}
[TestFixture]
public class RenderMvcControllerTests : BaseRoutingTest
{
protected override DatabaseBehavior DatabaseTestBehavior
{
get { return DatabaseBehavior.NoDatabasePerFixture; }
}
[Test]
public void CanGetIndex()
{
const int id = 1234;
var content = new Mock<IPublishedContent>();
content.Setup(c => c.Id).Returns(id);
var model = new RenderModel(content.Object, CultureInfo.InvariantCulture);
var blogService = new Mock<IBlogService>();
var entry = new Entry { Id = id };
blogService.Setup(s => s.GetBlogEntry(id)).Returns(entry);
var controller = GetBlogEntryController(blogService.Object);
var result = (ViewResult)controller.Index(model);
blogService.Verify(s => s.GetBlogEntry(id), Times.Once());
Assert.IsNotNull(result);
Assert.IsAssignableFrom<Entry>(result.Model);
}
private BlogEntryController GetBlogEntryController(IBlogService blogService)
{
var routingContext = GetRoutingContext("/test");
var umbracoContext = routingContext.UmbracoContext;
var contextBase = umbracoContext.HttpContext;
var controller = new BlogEntryController(blogService, umbracoContext);
controller.ControllerContext = new ControllerContext(contextBase, new RouteData(), controller);
controller.Url = new UrlHelper(new RequestContext(contextBase, new RouteData()), new RouteCollection());
return controller;
}
}
}
此代码仅在Umbraco 6.1.5中进行过测试。
答案 1 :(得分:1)
根据核心团队的说法,您应该包含Umbraco.Tests库并从BaseUmbracoApplicationTest继承您的测试。这将设置一个有效的UmbracoApplication和UmbracoContext。
https://groups.google.com/forum/?fromgroups=#!topic/umbraco-dev/vEjdzjqmtsU
答案 2 :(得分:0)
我在Umbraco论坛上提出了这个问题,并且有几个回复可能对你有所帮助。
见这里:
基本上,你可以..只是......但需要一些反思,因为一些关键类和接口是内部的。正如卢克的最后一篇文章指出的那样,这是因为该功能目前是一个移动目标。