web-dev-qa-db-fra.com

ASP.NET MVC: tests unitaires des contrôleurs qui utilisent UrlHelper

L'une de mes actions de contrôleurs, celle qui est appelée dans une demande Ajax, est de renvoyer une URL du côté client afin qu'il puisse effectuer une redirection. J'utilise Url.RouteUrl(..) et lors de mes tests unitaires, cela échoue car le paramètre Controller.Url N'est pas pré-rempli.

J'ai essayé beaucoup de choses, entre autres en essayant de bloquer UrlHelper (qui a échoué), en créant manuellement un UrlHelper avec un RequestContext qui a un HttpContextBase tronqué (qui a échoué lors d'un appel RouteCollection.GetUrlWithApplicationPath).

J'ai recherché Google mais n'ai trouvé pratiquement rien sur le sujet. Suis-je en train de faire quelque chose d'incroyablement stupide en utilisant Url.RouteUrl Dans mon action de contrôleur? Existe-t-il un moyen plus simple?

Pour aggraver encore les choses, j'aimerais pouvoir tester l'URL renvoyée dans mon test unitaire - en fait, je ne souhaite que savoir qu'elle redirige vers la bonne route, mais puisque je renvoie une URL au lieu d'un route, je voudrais contrôler l'URL qui est résolue (par exemple en utilisant un RouteCollection tronqué) - mais je serai heureux de réussir mon test pour commencer.

169
efdee

Voici l'un de mes tests (xUnit + Moq) juste pour un cas similaire (en utilisant Url.RouteUrl dans le contrôleur)

J'espère que cela t'aides:

var routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);

var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
request.SetupGet(x => x.ApplicationPath).Returns("/");
request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute));
request.SetupGet(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection());

var response = new Mock<HttpResponseBase>(MockBehavior.Strict);
response.Setup(x => x.ApplyAppPathModifier("/post1")).Returns("http://localhost/post1");

var context = new Mock<HttpContextBase>(MockBehavior.Strict);
context.SetupGet(x => x.Request).Returns(request.Object);
context.SetupGet(x => x.Response).Returns(response.Object);

var controller = new LinkbackController(dbF.Object);
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
controller.Url = new UrlHelper(new RequestContext(context.Object, new RouteData()), routes);
200
eu-ge-ne

Une implémentation modifiée de eu-ge-ne. Celui-ci renvoie un lien généré basé sur les routes définies dans l'application. L'exemple de eu-ge-ne a toujours renvoyé une réponse fixe. L'approche ci-dessous vous permettra de tester que l'action/le contrôleur et les informations de route corrects sont transmis à l'UrlHelper - c'est ce que vous voulez si vous testez l'appel à l'UrlHelper.

var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();

context.Setup(ctx => ctx.Request).Returns(request.Object);
context.Setup(ctx => ctx.Response).Returns(response.Object);
context.Setup(ctx => ctx.Session).Returns(session.Object);
context.Setup(ctx => ctx.Server).Returns(server.Object);

request.SetupGet(x => x.ApplicationPath).Returns("/");
request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute));
request.SetupGet(x => x.ServerVariables).Returns(new NameValueCollection());

response.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(x => x);

context.SetupGet(x => x.Request).Returns(request.Object);
context.SetupGet(x => x.Response).Returns(response.Object);

var routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);
var helper = new UrlHelper(new RequestContext(context.Object, new RouteData()), routes);
36
Steven Pena

Ce message peut être utile si vous souhaitez vous moquer de la classe HttpContextBase.

http://www.hanselman.com/blog/ASPNETMVCSessionAtMix08TDDAndMvcMockHelpers.aspx

12
Gerardo Contijoch

Construire la réponse de @ eu-ge-ne qui m'a beaucoup aidé:

J'avais un ActionResult qui a fait une redirection ainsi qu'un appel UpdateModel avec un paramètre FormCollection. Pour que UpdateModel () fonctionne, j'ai dû ajouter ceci à mon Mocked HttpRequestBase:

FormCollection collection = new FormCollection();
collection["KeyName"] = "KeyValue";

request.Setup(x => x.Form).Returns(collection);
request.Setup(x => x.QueryString).Returns(new NameValueCollection());

Pour tester que l'URL redirigée était correcte, vous pouvez procéder comme suit:

RedirectResult result = controller.ActionName(modelToSubmit, collection) as RedirectResult;
Assert.AreEqual("/Expected/URL", result.Url);
2
woopstash

http://kbochevski.blogspot.com/2010/06/unit-testing-mvcnet.html explique comment couvrir toutes les couches avec des tests unitaires. Il utilise Rhino et MVC.Contrib pour les tests des contrôleurs . Le code source sur google peut être d'une grande aide.

1
hurbata