Returning JsonResult From ASP.NET MVC 2.0 Controller and Unit Testing

* I’m adding this comment after the post has been written to let anyone coming here know of another great post that goes further to explain no only what I’ve done here, but also two other ways including Mock and using Json Serialization.  The Post is written by Ashic Mahtab, aka “HeartattacK” on the forums.  His well written and informative article is here:  ASP.NET MVC – Unit Testing JsonResult Returning Anonymous Types.

This post will show how to return a simple Json result from an ASP.NET MVC 2.0 web project.  It will show how to test that result inside a unit test and essentially pick apart the Json, just like a JavaScript (or other client) would do.  It seems like it should be very simple (and indeed, once you see the answer it is), however there are lots of length discussions on the forums about this with all kinds of positives and negatives.  The one I based my solution on is from Stack Overflow and is here..  My personal length discussion that did not really yield a satisfactory answer is here.

If you follow my method, you’ll be able to unit test a JsonResult created by an MVC asp.net web application.


Controller Side (Server)

Let’s get started. First thing we need to do is have a controller that return a JsonResult.  Below is the one I’m currently working on.  Let me show the code, then explain it.

 

public ActionResult Get(FormCollection form)
{
var query = new FolderPairQuery();
if (form["query"] != null)
{
query = form["query"].FromJson<FolderPairQuery>();
}

if (form["start"] != null && form["limit"] != null)
{
query.Start = Convert.ToInt32(form["start"]);
query.Limit = Convert.ToInt32(form["limit"]);
}

var results = FolderPairManager.I.Get(query);
return Json(new
{
success = true,
rows = results,
total = query.OutputTotal
}, JsonRequestBehavior.AllowGet);
}
 

This code is actually part of the file FolderPairController.cs.  It returns an ActionResult (which in this case is JsonResult that derives from ActionResult).  All the way to the return statement is just stuff that I do in my code to pull apart the passed in Request variables and process them.  I only leave them in for context.  It does not matter how you get your “results” and “total”, it just matters that you do. Then, the return statement is the part that is of interest.  It’s basically returning an anonymous class which is actually a JsonResult.  In System.Web.Mvc.Controller.cs, you will see that Json is defined as:

 

protected internal JsonResult Json(object data, JsonRequestBehavior behavior);
 
 
The first parameter is “object data” which means it can be anything, and in our case, it is an anonymous object.
 

Unit Test Side (Client)

 
So now, let’s take a look at the unit test itself.  Again, let me show the code, then explain it.
 
[TestMethod]
public void InsertControllerTest()
{
var pairName = string.Format("FolderPair {0}",
(new Random().Next(1, 10000)));
var folderPairResults =
new List<FolderPairResult>()
{
new FolderPairResult
{
ActionTypeId = 1,
CheckFileContent = true,
ActiveForRunAll = true,
ExcludeHiddenFiles = true,
ExcludeReadOnly = true,
ExcludeSystemFiles = true,
FolderPairName = pairName,
LeftFolder = "left",
RightFolder = "right",
SaveOverWrittenRecycleBin = true,
UsersId = 1
}
};



string jsonInsert = JsonConvert.SerializeObject(folderPairResults);

var form =
new FormCollection
{
{"data", jsonInsert}
};


using (var controller = new FolderPairController())
{

controller.Insert(form);
}

// verify it got inserted.
var queryObj = new FolderPairQuery { FolderPairName = pairName };
string json = JsonConvert.SerializeObject(queryObj);
var formGet =
new FormCollection()
{
{"query", json}
};

using (var controller = new FolderPairController())
{
var jsonResult1 = controller.Get(formGet) as JsonResult;
Assert.IsNotNull(jsonResult1,"jsonResult1 is null which is bad");


List<FolderPairResult> folderPairResults1 =
(List<FolderPairResult>)
(jsonResult1.Data.GetType().GetProperty("rows")).GetValue(jsonResult1.Data, null);
bool success =
(bool)
(jsonResult1.Data.GetType().GetProperty("success")).GetValue(jsonResult1.Data, null);
int total =
(int)
(jsonResult1.Data.GetType().GetProperty("total")).GetValue(jsonResult1.Data, null);

Assert.IsTrue(folderPairResults1.Count == 1, "Not one item returned");
Assert.IsTrue(folderPairResults1[0].FolderPairName.Equals(pairName),
"Wrong pairname returned");
}
}

Up to the line “// verify it got inserted”, we simply are adding the record to the database in our unit test.  I won’t go into detail about that in this post since it is not really the purpose here.  I’m really just trying to show how to extract from the JsonResult the values that are returned from the server.
 
So, notice the line “var jsonResult1 = controller.Get(formGet) as JsonResult;”.  This line simply calls the controller’s get method with the appropriate query parameters and returns us a JsonResult.  Now, let’s look at how to get the data out of that.  It’s really quite simple using reflection.  Each of the following three lines pulls the data out so that at the end, we have our typed data for rows,total and count.
 
Hopefully, this will help you.  Like I said in the beginning, there are lots of ways to do this.  This just shows one that works for me.
 
About Peter Kellner

Peter is a software professional specializing in mobile and web technologies. He has also been a Microsoft MVP for the past 7 years. To read more about Peter Kellner and his experience click here. For information about how Peter Kellner might be able to help you with your project click here.

Follow me:


Comments

  1. O thanks for the link Peter, I was looking at the code and found this page which also lead me to the post by Heartattack. Thanks!

  2. Please see the comment just added at the top of this post with a referral to a great post by HeartattacK on the same subject.

  3. @Peter: Visual studio unit test project, begs the question ;o)
    qunit.js gives me the opportunity to apply the testing methodology to my RIA projects, quite successfully. Pardon é moi, but I can not see what is the advantage of VS/C# unit tests? Or better validity?

    PHP: yes it is simpler but then it is too simple too. I am doing XML and JSON using ASP since 2001. I have no issue with C#. ASP.NET+MVC is tragic over-engineering, I think. Based on wrong kind of OO, I also dare to think.
    MVVM is better, but then curiously it is classified as “UI architectural pattern” ?

  4. Hi DBJ,

    I totally agree that the html page would be simpler and definitely makes the case for having browser based testing. My idea here is to have test testing itself run all in c# in a visual studio unit test project. That’s the reason for all the ugly encoding and decoding of javascript.

    I do see the simplicity of php and do like that. unit testing though really is for another purpose. I think you’d have the same fundadmental problems using php if you wanted to test without a browswer in the picture. That is, just test the controller logic.

    Thanks for you comments!

  5. Correct me if I am wrong, but would it be simpler, and a bit more valid, if this is tested from an html page, using JavaScript only?
    (side note:
    On the server side, I am totally lost trying to answer why is it done as it is done? Not your code Peter, but this whole “MVC2 solution”. Certainly “over-engineering” has been elevated to new heights by ASP.NET “evangelists” here. No wonder PHP is so successful , yet in the same time “inferior” to ASP.NET.
    )

  6. If anyone knows how to solve the Controller Test side using a ‘non’ reflector type solution (such as .net 4.0 dynamic type), I’d love to see that. Please post a comment with details. -Thanks

Follow

Get every new post delivered to your Inbox

Join other followers: