【问题标题】:Unit Testing a RenderMvcController even possible?甚至可以对 RenderMvcController 进行单元测试?
【发布时间】:2013-07-24 11:02:17
【问题描述】:

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

我已经在我的Global.ascx 中实现了IApplicationEventHandler,并且在运行应用程序时 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不能为null,但现在正在抛出:

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

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

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

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

谢谢。

【问题讨论】:

    标签: unit-testing umbraco


    【解决方案1】:

    要对 Umbraco RenderMvcController 进行单元测试,您需要 grab the source code from github,自行编译解决方案,并获取 Umbraco.Tests.dll 并在您的测试项目中引用它。

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

    为了帮助您解决这个问题,我为 Umbraco 6.1.5 编译了 Umbraco.Tests.dll 并将其与 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 中测试过。

    【讨论】:

    • 谢谢,我得到了类似的结果。不过,这是一项巨大的努力——希望未来能够从核心团队那里获得更多的 TLC。
    • @JorgeLusar,我正在尝试按照您的示例设置一个带有 TDD 的 umbraco 网站,但我的第一个测试总是失败。你能检查我的问题,看看你是否有同样的问题? stackoverflow.com/questions/22660255/umbraco-unit-tests-failing 谢谢!
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      看这里:

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

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

      【讨论】:

        猜你喜欢
        • 2010-10-19
        • 1970-01-01
        • 2010-09-22
        • 2017-09-27
        • 2021-03-17
        • 1970-01-01
        • 1970-01-01
        • 2010-12-26
        • 1970-01-01
        相关资源
        最近更新 更多