1

I have an Action that gets JSON data from Request.Form[0] and has calls into domain objects.

I am testing this method, but it seems impossible to set Request.Form.

I could extract the method to another that takes the string it returns, but that would just be a one line method and the Action would still be untested.

Is there a method to test this or another, more testable method to get the JSON data from a $.ajax() call?

StuperUser
  • 10,555
  • 13
  • 78
  • 137

2 Answers2

2

Personally I Use MVCContrib TestHelper to unit test my controller actions. It makes things very fun and easy.

So in your case assuming the following controller (disclaimer: absolutely never write something like this in a real application, it's just an example here, in a real world application controller actions should never fetch stuff from Request.Form, they should use strongly typed action parameters and leave the default model binder do the parsing, etc...):

public class MyViewModel
{
    public string SomeProperty { get; set; }
}

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var json = Request.Form[0];
        var model = new JavaScriptSerializer().Deserialize<MyViewModel>(json);
        return View(model);
    }
}

you could test it like this:

// arrange
var builder = new TestControllerBuilder();
var sut = new HomeController();
builder.InitializeController(sut);
builder.Form.Add("foo", "{ someProperty: 'some value' }");

// act
var actual = sut.Index();

// assert
actual
    .AssertViewRendered()
    .WithViewData<MyViewModel>()
    .SomeProperty
    .ShouldEqual("some value", "");
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • What would a method signature for an Action that would receive a single string from a $.ajax() request be? Is there a better way to send it than JSON? – StuperUser Jan 19 '11 at 17:11
  • @StuperUser, like this: `public ActionResult Index(MyViewModel model) { ... }`. In ASP.NET MVC 3 the default model binder is [capable of parsing JSON](http://davidhayden.com/blog/dave/archive/2011/01/07/JsonValueProviderFactoryASPNETMVC3.aspx). If you are using older versions you could always write a [custom JsonValueProviderFactory](http://haacked.com/archive/2010/04/15/sending-json-to-an-asp-net-mvc-action-method-argument.aspx). But in neither case you should be using `Request.Form[0]` or `Request.Form["foo"]` in a controller action :-) – Darin Dimitrov Jan 19 '11 at 17:19
  • Thanks Darin, that's great. I'll have a look at MVCContrib too. – StuperUser Jan 19 '11 at 17:54
  • @StuperUser, yeah MVCContrib is something worth looking to if you are building something more serious than a blog application with ASP.NET MVC :-) (don't get it wrong, I have nothing against blog applications) – Darin Dimitrov Jan 19 '11 at 17:56
0

It's possible to pass a strongly typed string parameter writing it into the method, by adding it as a parameter

public JsonResult ActionName(string paramName)

and including it in the data:

var dataVar = getDataVar();
$.ajax({
    url: '/Controller/ActionName'
    , type: 'post'
    , data: { paramName: dataVar }
    , dataType: 'json'

    , success: function (returnJSON) {
    }
    , error: function (XMLHttpRequest, textStatus, errorThrown) {
    //error handle in here
    }
});
StuperUser
  • 10,555
  • 13
  • 78
  • 137