2009-09-02 19 views
21

Gli URL per i menu nelle mie app ASP.NET MVC vengono generati dal controller/azioni. Quindi, chiamanoASP.NET MVC: Mock controller.Url.Action

controller.Url.Action(action, controller) 

Ora, come faccio a fare questo lavoro in unit test? Io uso MvcContrib con successo con

var controller = new TestControllerBuilder().CreateController<OrdersController>(); 

ma tutto quello che cerco di fare con esso ho controller.Url.Action (azione, di controllo) in mancanza con NullReferenceException perché URL == null.

Aggiornamento: non si tratta di come intercettare HttpContext. L'ho fatto in diversi modi, usando MVCContrib, l'esempio di falso di Scott Hanselman e anche quello di http://stephenwalther.com/blog/archive/2008/07/01/asp-net-mvc-tip-12-faking-the-controller-context.aspx. Questo non mi aiuta perché ho bisogno di sapere quali valori falsi ... è ApplicationPath? Come lo installo? Deve corrispondere al controller/azione chiamato? Cioè, come funziona Url.Action e come posso soddisfarlo?

Inoltre, so che posso fare IUrlActionAbstraction e seguirlo ... ma non sono sicuro di volerlo fare. Dopo tutto, ho MVCContrib/Mock a piena potenza e perché ho bisogno di un'altra astrazione.

+0

Qual è la tua suite di test? –

+1

Non vale una risposta da solo, quindi indicherò una risposta simile: http://bit.ly/aSJ0a –

+0

Sì, ho usato quel collegamento e non ha funzionato. In realtà ho provato sia la versione di Scott che MVCContrib. Quello che cerco di capire è quali valori devo impostare? Cosa usa effettivamente Url.Action()? Cioè sul link che hai fornito c'è la versione di Moq che imposta un sacco di variabili ... sono TUTTE le necessarie? Ho provato tutti loro senza fortuna. – queen3

risposta

21

Ecco come si potrebbe prendere in giro UrlHelper usando TestControllerBuilder di MvcContrib:

var routes = new RouteCollection(); 
MvcApplication.RegisterRoutes(routes); 
HomeController controller = CreateController<HomeController>(); 

controller.HttpContext.Response 
    .Stub(x => x.ApplyAppPathModifier("/Home/About")) 
    .Return("/Home/About"); 

controller.Url = new UrlHelper(
    new RequestContext(
     controller.HttpContext, new RouteData() 
    ), 
    routes 
); 
var url = controller.Url.Action("About", "Home"); 
Assert.IsFalse(string.IsNullOrEmpty(url)); 
+0

Oops ... È stato fuorviante vedere nella guida MSDN per Controller.Url "Ottiene l'oggetto helper URL" ... Non ho nemmeno verificato se ha setter. – queen3

+0

Sai come possiamo ottenere questo risultato con MVC4 Darin? Mentre sto cercando di seguire il tuo esempio di codice ma non riesco a chiamare RegisterRoutes – DevDave

+2

Tyler: RegisterRoutes è una convenzione, usa MvcApplication.RouteTable.Routes.Add (...) – Shane

3

fingere opere facile piacevolmente:

var fakeUrlHelper = A.Fake<UrlHelper>(); 
     controller.Url = fakeUrlHelper; 
     A.CallTo(() => fakeUrlHelper.Action(A<string>.Ignored, A<string>.Ignored)) 
      .Returns("/Action/Controller"); 
+0

+1 bazillion per l'uso di 'FakeItEasy' !! Ma ... il metodo 'Action' non è virtuale ... quindi come puoi fingere/intercettare quello? –

3

Se stai usando Moq (e non MvcContrib s' TestControllerBuilder), è può prendere in giro il contesto, simile alla risposta @ DarianDimitrov:

var controller = new OrdersController(); 
var context = new Mock<System.Web.HttpContextBase>().Object; 

controller.Url = new UrlHelper(
    new RequestContext(context, new RouteData()), 
    new RouteCollection() 
); 

Questo non imposta la proprietà controller.HttpContext, ma consente di eseguire Url.Action (e restituire una stringa vuota - non è richiesto il mocking).

13

un modo più pulito per fare questo è sufficiente utilizzare Moq (o qualsiasi altro quadro che ti piace) per deridere UrlHelper sé

var controller = new OrdersController(); 
var Mock<UrlHelper> UrlHelperMock = new Mock<UrlHelper>(); 

controller.Url = UrlHelperMock.Object; 

UrlHelperMock.Setup(x => x.Action("Action", "Controller", new {parem = "test"})).Returns("testUrl"); 

var url = controller.Url.Action("Action", "Controller", new {parem = "test"}); 
assert.areEqual("/Controller/Action/?parem=test",url); 

pulito e semplice.