What is the best way to unit test a simple JsonResult?
-
26-02-2021 - |
Question
In the event of a successful AJAX call I want to return a simple object with Success = true
public ActionResult Foo(int id)
{
// ...
return Json(new {Success=true});
}
This works fine and the object my javascript receives looks like
{ Success : true }
but because the object returned is an anonymous type, I can't do (something like) the following in my test:
var result = (JsonResult)controller.AddNote(id, message);
dynamic data = result.Data;
// Assert
Assert.That(data.Success, Is.EqualTo(true));
So I tried returning an ExpandoObject which allows the test to work in the way I want but the the JSON sent back in the AJAX response is a mess, as detailed in this question.
[{"Key":"Success","Value":true}]
Is there a simple, clean way to achieve what seems like it should be easy, or is the only way to implement some custom serialization as in the linked question?
Solution
- Get the value with
dynamic
can work if you mark your controller assembly with the[assembly: InternalsVisibleTo("TestsProject")]
. Because the classes generated for anonymous types are internal and runtime binding does not work with internal types. In this article you can find more information about this. If you don't like this approach you can fallback to plain old reflection (hidden behind some helper methods):
[TestMethod] public void AddNote1() { ... var result = ((JsonResult)controller.AddNote(id, message)); var data = result.Data; // Assert Assert.AreEqual(Get<bool>(data, "Success"), true); } private T Get<T>(object instance, string propertyName) { return (T) instance.GetType().GetProperty(propertyName).GetValue(instance, null); }
Use named classes instead of anonymous ones.
You have to use some kind of serialization workaround as you mentioned.
OTHER TIPS
What you can do is:
var js = new JavaScriptSerializer();
var response = new { id = 0, Status = false };
dynamic object = js.Deserialize(new StringReader(JSONText), response.GetType());
Assert.IsTrue(object.Success)
What this does is:
- Create a JavaScriptSerializer.
- Create a new anonymous object with the same layout as your json, so the serialiser knows what your object looks like
- Deserialize the json into a new dynamic object.
The disadvantage of this is that you will not have IntelliSense on your json object, so any spelling mistake will not be caught by the compiler.
Note: I wrote the code here in stackoverflow, so there might be minor bugs in it. I did not test it, but it should work :P