2009-09-02 15 views
21

Adresy URL dla menu w moich aplikacjach ASP.NET MVC są generowane przez kontroler/akcje. Tak więc nazywają się:ASP.NET MVC: Mock controller.Url.Action

controller.Url.Action(action, controller) 

Jak to zrobić w testach jednostkowych? używam MvcContrib powodzeniem

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

ale co staram się zrobić z niego uzyskać controller.Url.Action (akcja, kontroler) w przypadku braku z NullReferenceException ponieważ Url == null.

Aktualizacja: nie chodzi o przechwycenie HttpContext. Zrobiłem to na kilka sposobów, używając MVCContrib, przykładu udawania Scotta Hanselmana, a także tego z http://stephenwalther.com/blog/archive/2008/07/01/asp-net-mvc-tip-12-faking-the-controller-context.aspx. To mi nie pomaga, ponieważ muszę wiedzieć, jakie wartości warto fałszować ... czy to jest ApplicationPath? Jak to skonfigurować? Czy musi pasować do nazwanego kontrolera/działania? To znaczy, jak działa Url.Action i jak mogę go zaspokoić?

Ponadto, wiem, że mogę zrobić IUrlActionAbstraction i iść z tym ... ale nie jestem pewien, czy chcę to zrobić. W końcu mam pełną moc MVCContrib/Mock i dlaczego potrzebuję kolejnej abstrakcji.

+0

Jaki jest twój pakiet testowy? –

+1

Nie warto odpowiedzieć sam, więc wskażę podobną odpowiedź: http://bit.ly/aSJ0a –

+0

Tak, użyłem tego linku i nie zadziałało. Właściwie próbowałem obu wersji Scotta i MVCContrib. Co staram się zrozumieć, jakie wartości muszę skonfigurować? Co właściwie używa Url.Action()? To znaczy. na podanym linku znajduje się wersja Moq, która konfiguruje wiele zmiennych ... czy WSZYSTKIE z nich są potrzebne? Wypróbowałem je wszystkie bez szczęścia. – queen3

Odpowiedz

21

Oto jak można kpić UrlHelper użyciu MvcContrib za TestControllerBuilder:

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

Ups ... Wprowadzanie w błąd w pomocy MSDN dla Controller.Url "Pobiera obiekt pomocnika URL" ... Nie sprawdziłem nawet, czy ma ustawnik. – queen3

+0

Czy wiesz, jak mogliśmy to osiągnąć dzięki MVC4 Darin? Ponieważ próbuję podążać za przykładem twojego kodu, ale nie mogę zadzwonić do RegisterRoutes – DevDave

+2

Tyler: RegisterRoutes jest konwencją, użyj MvcApplication.RouteTable.Routes.Add (...) – Shane

3

Fałszywe it easy działa dobrze:

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

+1 miliard za używanie 'FakeItEasy' !! Ale ... metoda "działania" nie jest wirtualna ... więc jak możesz ją sfałszować/przechwycić? –

3

Jeśli używasz Moq (i nie MvcContrib „s TestControllerBuilder), ty może wyśmiewać kontekst, podobny do @ DarianDimitrov's odpowiedź:

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

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

Nie ustawia to właściwości controller.HttpContext, ale zezwala na wykonanie Url.Action (i zwraca pusty ciąg - nie wymaga szyderstwa).

13

Czystsze sposobem na to jest po prostu użyć Min (lub jakakolwiek inna struktura chcesz) mock UrlHelper się

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

czyste i proste.