6

In my Asp.net MVC app, I have two methods on a controller, one for when the user first arrives on the view and then one when they submit the form on said view.

public ActionResult Foo() {}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Foo(string id, Account accountToFoo) {}

In the second action, there's a custom model binder that's assembling the account object that I'm acting on, though that's really not important. This all works fine in testing locally on a server.

We try to be pretty good about writing unit tests to test all our different views are properly getting routed to, including those that are HTTP POST. To do so, we've been using mvccontrib's test helper.

Testing gets have been super simple

"~/account/foo/myusername".
       Route().
       ShouldMapTo<AccountController>(c => c.Foo("myusername"));

My question is in testing POST routes, how do I write the lambda that I would use to verify the post is receiving accurate values, similar to the GET test above?

For a POST, it looks something like:

"~/account/foo".
         WithMethod(HttpVerbs.Post).
         ShouldMapTo<AccountController>(a => something_something);

It's the something_something portion of my lambda that I'm having trouble with. Using arbitrary values doesn't work ("a => a.Foo(0, new Account()"). How would I specify the expected values as part of the test?

EDIT I was hoping there was something akin to the way Moq has lambdas for statements such as foo.Setup(s => s.Foo(It.IsAny(), It.Is(i => i > 32)) and so on. Even I have to explicitly supply the values, that's workable--I just can't seem to grok the desired structure to pass those explicit values.

bakasan
  • 2,262
  • 2
  • 26
  • 33
  • Did you ever resolve this problem? – Paul Feb 01 '10 at 13:27
  • Nope, never did--and got distracted with other parts of my new app that unit testing these particular POST actions fell by the wayside. Would still love to know how best to approach this. – bakasan Feb 02 '10 at 09:40

2 Answers2

15

Here's an example. Assuming you have the following action:

public AccountController : Controller
{
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Foo(string id) 
    {
        return View();
    }
}

And the following route registered:

RouteTable.Routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "home", action = "index", id = "" }
);

You could test it like this:

var routeData = "~/account/foo".WithMethod(HttpVerbs.Post);
routeData.Values["id"] = "123";
routeData.ShouldMapTo<AccountController>(c => c.Foo("123"));

Some tweaking might be necessary to include the second Account argument you have.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Oddly enough this scenario doesn't work for me. I have an 2 actions on the same controller, one labelled for HttpGet and one for HttpPost. I can comment out the HttpPost method (same name as the HttpGet, but with a different signature) and my test will still pass using the example you provided in the "You could test it like this" comment above. Here's the link to my question if you have any ideas: http://stackoverflow.com/questions/4157161/issue-with-mvccontrib-testhelper-fluent-route-testing-and-specific-httpverbs – Danny Douglass Nov 11 '10 at 20:59
2

Using the mvccontrib helper syntax:

"~/account/foo".WithMethod(HttpVerbs.Post).ShouldMapTo<AccountController>(a => a.foo(null));

You pass null as the Foo(string id, Account accountToFoo) method is never executed as part of the routing test.

Paul
  • 2,543
  • 3
  • 26
  • 36