问题
So I'm working with Umbraco 6.12 and having great difficulty been able to test a RenderMvcController
.
I have implemented IApplicationEventHandler
in my Global.ascx
and Ninject is working fine and as expected when running the application - all good.
However, unit testing these controllers is a different matter. I found this, and have added the latest reply:
http://issues.umbraco.org/issue/U4-1717
I now have this lovely hack in my SetUp:
Umbraco.Web.UmbracoContext.EnsureContext(new HttpContextWrapper(new HttpContext(new HttpRequest("", "http://www.myserver.com", ""), new HttpResponse(null))), ApplicationContext.Current);
Which has got around the original UmbracoContext
cannot be null, but is now throwing:
Current has not been initialized on Umbraco.Web.PublishedCache.PublishedCachesResolver. You must initialize Current before trying to read it.
The published caches resolver also seems to be hidden behind internal and protected stuff, which I can't use reflection to hack at as I can't init anything to pass into SetProperty
reflection.
It's really frustrating, I'm loving v6, and using uMapper is very nice. I can inject a repo, service, command or query at will into the controllers and life is good - I just can't cover the controllers!
Any help on this would be greatly appreciated.
Thanks.
回答1:
To unit test a Umbraco RenderMvcController, you need to grab the source code from github, compile the solution yourself, and get the Umbraco.Tests.dll and reference it on your test project.
In addition to that, you need to reference the SQLCE4Umbraco.dll which is distributed with the Umbraco packages, and Rhino.Mocks.dll which is internally for mocking.
To help you with this, I have compiled put the Umbraco.Tests.dll for Umbraco 6.1.5 and put it together with the Rhino.Mocks.dll and put it on this zip file.
Finally, derive your test from BaseRoutingTest, override the DatabaseTestBehavior to NoDatabasePerFixture, and get the UmbracoContext and HttpBaseContext by calling the GetRoutingContext method, as in the code below:
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;
}
}
}
This code has only been tested in Umbraco 6.1.5.
回答2:
According to the core team, you should include the Umbraco.Tests library and inherit your test from BaseUmbracoApplicationTest. That will setup a valid UmbracoApplication and UmbracoContext.
https://groups.google.com/forum/?fromgroups=#!topic/umbraco-dev/vEjdzjqmtsU
回答3:
I have raised this on the Umbraco forums and there are several replies which may help you.
See here:
http://our.umbraco.org/forum/developers/api-questions/37255-How-can-I-unit-test-a-class-inheriting-from-SurfaceController
Essentially, you can .. just ... but requires some reflection because some of the key classes and interfaces are internal. As Luke's last post points out, this is because the functionality is currently a bit of a moving target.
来源:https://stackoverflow.com/questions/17832096/unit-testing-a-rendermvccontroller-even-possible