6

所以我正在使用 Umbraco 6.12 并且很难测试RenderMvcController.

我已经IApplicationEventHandler在我的应用程序中实现了,Global.ascx并且 Ninject 在运行应用程序时工作正常并且符合预期 - 一切都很好。

但是,对这些控制器进行单元测试是另一回事。我找到了这个,并添加了最新的回复:

http://issues.umbraco.org/issue/U4-1717

我现在在我的设置中有这个可爱的 hack:

 Umbraco.Web.UmbracoContext.EnsureContext(new HttpContextWrapper(new HttpContext(new HttpRequest("", "http://www.myserver.com", ""), new HttpResponse(null))), ApplicationContext.Current);

绕过原来的UmbracoContext不能为空,但现在抛出:

Current 尚未在 Umbraco.Web.PublishedCache.PublishedCachesResolver 上初始化。您必须在尝试读取 Current 之前对其进行初始化。

发布的缓存解析器似乎也隐藏在内部和受保护的东西后面,我不能使用反射来破解,因为我无法初始化任何东西来传递给SetProperty反射。

这真的很令人沮丧,我喜欢 v6,并且使用 uMapper 非常好。我可以随意将 repo、服务、命令或查询注入到控制器中,而且生活很好——我只是无法覆盖控制器!

对此的任何帮助将不胜感激。

谢谢。

4

3 回答 3

10

要对 Umbraco RenderMvcController 进行单元测试,您需要从 github 获取源代码,自己编译解决方案,并获取 Umbraco.Tests.dll 并在您的测试项目中引用它。

除此之外,您还需要引用随 Umbraco 包分发的 SQLCE4Umbraco.dll,以及内部用于模拟的 Rhino.Mocks.dll。

为了帮助您解决这个问题,我编译了 Umbraco 6.1.5 的 Umbraco.Tests.dll 并将其与 Rhino.Mocks.dll 放在一起并放在这个 zip 文件中。

最后,从 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 中测试过。

于 2013-09-18T10:01:34.753 回答
1

根据核心团队的说法,您应该包含 Umbraco.Tests 库并从 BaseUmbracoApplicationTest 继承您的测试。这将设置一个有效的 UmbracoApplication 和 UmbracoContext。

https://groups.google.com/forum/?fromgroups=#!topic/umbraco-dev/vEjdzjqmtsU

于 2013-08-29T21:53:03.680 回答
0

我在 Umbraco 论坛上提出了这个问题,有几个回复可能会对你有所帮助。

看这里:

http://our.umbraco.org/forum/developers/api-questions/37255-How-can-I-unit-test-a-class-inheriting-from-SurfaceController

本质上,您可以……只是……但需要一些反射,因为一些关键类和接口是内部的。正如 Luke 的最后一篇文章所指出的,这是因为该功能目前有点移动目标。

于 2013-07-25T11:19:35.477 回答