How to unit test a route using custom model binding

I have a custom mediator that checks to see if the user has access to the document that he requested; I want to know how can I check the route that this custom binder uses?

I am trying to run this test but getting this error:

MvcContrib.TestHelper.AssertionException: The value for the contract parameter does not match: expected 'Domain.Models.Contract', but was ''; in the context of the route there is no value for the action parameter called "contract" - does your corresponding route contain a token called "contract"?

[SetUp] public void Setup() { MvcApplication.RegisterModelBinders(); MvcApplication.RegisterRoutes(RouteTable.Routes); } [Test] public void VersionEdit() { var contract = TestHelper.CreateContract(); var route = "~/Contract/" + contract.Id.ToString() + "/Version/Edit/" + contract.Versions.Count; route.ShouldMapTo<VersionController>(c => c.Edit(contract)); } 

If I try to debug, a custom binder will never be called.

Defining my route:

 public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "VersionToken", // Route name "Contract/{contractId}/Version/{version}/{action}/{token}", // URL with parameters new { controller = "Version", action = "ViewContract", version = 1, token = UrlParameter.Optional } // Parameter defaults ); routes.MapRoute( "Version", // Route name "Contract/{contractId}/Version/{version}/{action}", // URL with parameters new { controller = "Version", action = "Create", version = UrlParameter.Optional } // Parameter defaults ); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults ); if (HttpContext.Current != null && !HttpContext.Current.IsDebuggingEnabled) routes.IgnoreRoute("CI"); } 

My Model binder:

 public static void RegisterModelBinders() { var session = (ISession)DependencyResolver.Current.GetService(typeof(ISession)); var authService = (IAuthenticationService)DependencyResolver.Current.GetService(typeof(IAuthenticationService)); System.Web.Mvc.ModelBinders.Binders[typeof (Contract)] = new ContractModelBinder(session, authService); } public class ContractModelBinder : DefaultModelBinder { private readonly ISession _session; private readonly IAuthenticationService _authService; public ContractModelBinder(ISession session, IAuthenticationService authService) { _session = session; _authService = authService; } public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var contractId = GetValue(bindingContext, "contractId"); var version = GetA<int>(bindingContext,"version"); var token = GetValue(bindingContext, "token"); var contract = _session.Single<Contract>(contractId); if (contract == null) { throw new HttpException(404, "Not found"); } if (contract.Versions.Count < version.Value) { throw new HttpException(404, "Not found"); } contract.RequestedVersionNumber = version.Value; if(token == null) { var user = _authService.LoggedUser(); if (user == null) throw new HttpException(401, "Unauthorized"); if (contract.CreatedBy == null || !contract.CreatedBy.Id.HasValue || contract.CreatedBy.Id.Value != user.Id) { throw new HttpException(403, "Forbidden"); } } else { contract.RequestedToken = token; var userToken = contract.RequestedVersion.Tokens.SingleOrDefault(x => x.Token == token); if (userToken == null) { throw new HttpException(401, "Unauthorized"); } } return contract; } private static T? GetA<T>(ModelBindingContext bindingContext, string key) where T : struct, IComparable { if (String.IsNullOrEmpty(key)) return null; //Try it with the prefix... var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + "." + key); //Didn't work? Try without the prefix if needed... if (valueResult == null && bindingContext.FallbackToEmptyPrefix) { valueResult = bindingContext.ValueProvider.GetValue(key); } if (valueResult == null) { return null; } return (T)valueResult.ConvertTo(typeof(T)); } private static string GetValue(ModelBindingContext bindingContext, string key) { if (String.IsNullOrEmpty(key)) return null; //Try it with the prefix... var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + "." + key); //Didn't work? Try without the prefix if needed... if (valueResult == null && bindingContext.FallbackToEmptyPrefix) { valueResult = bindingContext.ValueProvider.GetValue(key); } if (valueResult == null) { return null; } return valueResult.AttemptedValue; } } 
+4
source share
1 answer

When testing routes, the MvcContrib TestHelper does not invoke the MVC pipeline and model binding. Model binder must be tested separately. Binding is separate from routing and occurs after the controller instance is created and the action is called.

In this example, you are module testing modules. Therefore, you need to make sure that ~/Contract/5/Version/Edit/3 correctly displays the Edit action on your VersionController , which is executed as follows:

 "~/Contract/5/Version/Edit/3".ShouldMapTo<VersionController>(c => c.Edit(null)); 
+5
source

Source: https://habr.com/ru/post/1347474/


All Articles