2013-07-24 14 views
6

Also arbeite ich mit Umbraco 6.12 und mit großen Schwierigkeiten in der Lage, eine RenderMvcController zu testen.Unit Testen eines RenderMvcControllers sogar möglich?

Ich habe IApplicationEventHandler in meinem Global.ascx implementiert und Ninject funktioniert gut und wie erwartet beim Ausführen der Anwendung - alles gut.

Das Testen dieser Controller ist jedoch eine andere Sache. Ich fand dies und haben die neueste Antwort hinzugefügt:

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

ich jetzt habe dieses schöne Hack in meine SetUp:

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

, die um den ursprünglichen UmbracoContext kann nicht null sein, bekommen hat, ist aber Jetzt werfen:

Der aktuelle wurde nicht auf Umbraco.Web.PublishedCache.PublishedCachesResolver initialisiert. Sie müssen Current initialisieren, bevor Sie versuchen, es zu lesen.

Der veröffentlichte Caches Resolver scheint auch hinter internen und geschützten Sachen versteckt zu werden, was ich nicht Reflexion an hacken verwenden kann, wie ich etwas nicht init kann in SetProperty Reflexion passieren.

Es ist wirklich frustrierend, ich liebe v6, und die Verwendung von uMapper ist sehr nett. Ich kann nach Belieben ein Repo, einen Service, einen Befehl oder eine Abfrage in die Controller einfügen und das Leben ist gut - ich kann die Controller einfach nicht abdecken!

Jede Hilfe zu diesem würde sehr geschätzt werden.

Danke.

Antwort

10

um Unit-Test ein Umbraco RenderMvcController, müssen Sie grab the source code from github, die Lösung selbst kompilieren, und die Umbraco.Tests.dll bekommen und es auf Ihrem Testprojekt verweisen.

Zusätzlich müssen Sie auf die SQLCE4Umbraco.dll verweisen, die mit den Umbraco-Pakete verteilt wird, und Rhino.Mocks.dll, die intern für Spott ist.

Um Ihnen dabei zu helfen, habe ich die Umbraco.Tests.dll für Umbraco 6.1.5 zusammengestellt und zusammen mit der Rhino.Mocks.dll erstellt und auf this zip file gesetzt.

Schließlich leiten Sie Ihre Test von BaseRoutingTest, überschreiben die DatabaseTestBehavior zu NoDatabasePerFixture und erhalten die UmbracoContext und HttpBaseContext durch die GetRoutingContext Methode aufrufen, wie in dem folgenden Code:

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; 
     } 
    } 
} 

Dieser Code wurde nur getestet in Umbraco 6.1.5.

+0

Danke, ich endete mit ähnlichen. Es ist jedoch eine große Anstrengung - hoffentlich wird dies ein bisschen mehr TLC aus dem Kernteam in der Zukunft. – Jammin

+0

@JorgeLusar, Ich versuche, eine Umbraco-Website mit TDD einzurichten, indem ich Ihrem Beispiel folge, aber mein erster Test schlägt immer fehl. Können Sie bitte meine Frage überprüfen und sehen, ob Sie das gleiche Problem hatten? http://stackoverflow.com/questions/22660255/umbraco-unit-tests-failing Vielen Dank! –

0

Ich habe dies auf den Umbraco Foren angesprochen und es gibt mehrere Antworten, die Ihnen helfen können.

Siehe hier:

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

Im Wesentlichen können Sie .. nur ... aber einige Überlegungen erfordern, weil einige der wichtigsten Klassen und Schnittstellen intern sind. Wie Lukas letzter Beitrag darauf hinweist, liegt das daran, dass die Funktionalität derzeit ein bewegliches Ziel ist.

Verwandte Themen