2013-07-24 9 views
6

Quindi sto lavorando con Umbraco 6.12 e ho avuto grande difficoltà a testare uno RenderMvcController.Unit testing di RenderMvcController anche possibile?

Ho implementato IApplicationEventHandler nel mio Global.ascx e Ninject funziona correttamente e come previsto durante l'esecuzione dell'applicazione - tutto bene.

Tuttavia, l'unità che esegue il test di questi controller è diversa. Ho trovato questo, e hanno aggiunto l'ultima risposta:

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

ora ho questa bella mod nella mia messa a punto:

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

che ha ottenuto intorno all'originale UmbracoContext non può essere nullo, ma è ora lancio:

La corrente non è stata inizializzata su Umbraco.Web.PublishedCache.PublishedCachesResolver. È necessario inizializzare Current prima di provare a leggerlo.

La cache resolver pubblicato sembra anche essere nascosto dietro roba interna e protetta, che non posso utilizzare la reflection per incidere a come non posso init nulla per passare nel SetProperty riflessione.

È davvero frustrante, sto amando la v6 e usare uMapper è molto bello. Posso iniettare un repo, un servizio, un comando o una query a piacimento nei controller e la vita è buona - non riesco a coprire i controller!

Qualsiasi aiuto su questo sarebbe molto apprezzato.

Grazie.

risposta

10

Per unit test un Umbraco RenderMvcController, è necessario grab the source code from github, compilare la soluzione da soli, e ottenere l'Umbraco.Tests.dll e di riferimento sul vostro progetto di test.

In aggiunta a ciò, è necessario fare riferimento al SQLCE4Umbraco.dll che è distribuito con i pacchetti Umbraco e Rhino.Mocks.dll che è internamente per il mocking.

Per aiutarvi con questo, ho compilato il file Umbraco.Tests.dll per Umbraco 6.1.5 e lo metto insieme a Rhino.Mocks.dll e lo metto su this zip file.

Infine, derivare il test da BaseRoutingTest, ignorare il DatabaseTestBehavior a NoDatabasePerFixture, e ottenere l'UmbracoContext e HttpBaseContext chiamando il metodo GetRoutingContext, come nel codice qui sotto:

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

Questo codice è stato testato solo in Umbraco 6.1.5.

+0

Grazie, ho finito con simili. È comunque un grande sforzo, si spera che questo abbia un po 'più di TLC dal core team in futuro. – Jammin

+0

@JorgeLusar, sto cercando di installare un sito web di umbraco con TDD seguendo il tuo esempio ma il mio primo test fallisce sempre. Puoi verificare la mia domanda e vedere se hai avuto lo stesso problema? http://stackoverflow.com/questions/22660255/umbraco-unit-tests-failing Grazie! –

0

Ho sollevato questo messaggio nei forum di Umbraco e ci sono diverse risposte che potrebbero aiutarti.

vedere qui:

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

In sostanza, si può .. solo ... ma richiede qualche riflessione perché alcune delle classi principali e le interfacce sono interni. Come sottolinea l'ultimo post di Luke, ciò è dovuto al fatto che la funzionalità è attualmente un obiettivo in movimento.