* 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);
Unit Test Side (Client)
[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");
}
}