routes.MapRoute(null,and ProductController's List method
"product/{category}",
new { controller = "Product", action = "List", category = UrlParameter.Optional });
public ActionResult List(string category = null)And here are a few attempts to test the route (with MVC Contrib Test Helper support)
{
IList<Product> products;
if (category == null)
{
products = _productRepository.GetAll();
}
else
{
products = _productRepository.GetAllByCategory(category);
}
return View(products);
}
First attempt
I have a compile error: "An expression tree may not contain a call or invocation that uses optional arguments". Grrrr, expressions don't play with optional arguments.
"~/product".Route().ShouldMapTo<ProductController>(c => c.List());
Second attempt
The test throws a MvcContrib.TestHelper.AssertionException: "Value for parameter 'category' did not match: expected 'System.Web.Mvc.UrlParameter' but was ''."
"~/product".Route().ShouldMapTo<ProductController>(c => c.List(null));
Third attempt
Same result as second attempt. Grrrr...
"~/product".Route().ShouldMapTo<ProductController>(c => c.List(""));
And the forth attempt
Now the test pass.
var routeData = "~/product".WithMethod(HttpVerbs.Get);
routeData.Values["category"] = null;
routeData.ShouldMapTo<ProductController>(c => c.List(null));
Why? 'category' is an optional parameter, as mentioned here, I expect that I don't need to explicit to define it in route value dictionary and the third attempt should be passed. Is a place to improve MVC Contrib test helper?
Here is a little helper extension method that works well. You can now change your example to something like below.
ReplyDelete"~/product".Route()
.SetOptionalParametersToNull()
.ShouldMapTo(c=>c.List(null));
public static class RouteExtenstions
{
public static RouteData SetOptionaltParametersToNull(this RouteData data)
{
var optionalParameters = data.Values.Where(keyValuePair => keyValuePair.Value == UrlParameter.Optional)
.Select(x => x.Key).ToList();
foreach (var optionalParameter in optionalParameters)
data.Values[optionalParameter] = null;
return data;
}
}