How to unit test an Action method which returns JsonResult?
RPM, you look to be correct. I still have much to learn about dynamic
and I cannot get Marc's approach to work either. So here is how I was doing it before. You may find it helpful. I just wrote a simple extension method:
public static object GetReflectedProperty(this object obj, string propertyName)
{
obj.ThrowIfNull("obj");
propertyName.ThrowIfNull("propertyName");
PropertyInfo property = obj.GetType().GetProperty(propertyName);
if (property == null)
{
return null;
}
return property.GetValue(obj, null);
}
Then I just use that to do assertions on my Json data:
JsonResult result = controller.MyAction(...);
...
Assert.That(result.Data, Is.Not.Null, "There should be some data for the JsonResult");
Assert.That(result.Data.GetReflectedProperty("page"), Is.EqualTo(page));
I know I'm a bit late on this guys, but I found out why the dynamic solution wasn't working:
JsonResult
returns an anonymous object and these are, by default, internal
, so they need to be made visible to the tests project.
Open your ASP.NET MVC application project and find
AssemblyInfo.cs
from folder called Properties. Open AssemblyInfo.cs and add the following line to the end of this file.
[assembly: InternalsVisibleTo("MyProject.Tests")]
Quoted from: http://weblogs.asp.net/gunnarpeipman/archive/2010/07/24/asp-net-mvc-using-dynamic-type-to-test-controller-actions-returning-jsonresult.aspx
I thought it would be nice to have this one for the record. Works like a charm
I'm a bit late to the party, but I created a little wrapper that lets me then use dynamic
properties. As of this answer I've got this working on ASP.NET Core 1.0 RC2, but I believe if you replace resultObject.Value
with resultObject.Data
it should work for non-core versions.
public class JsonResultDynamicWrapper : DynamicObject
{
private readonly object _resultObject;
public JsonResultDynamicWrapper([NotNull] JsonResult resultObject)
{
if (resultObject == null) throw new ArgumentNullException(nameof(resultObject));
_resultObject = resultObject.Value;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (string.IsNullOrEmpty(binder.Name))
{
result = null;
return false;
}
PropertyInfo property = _resultObject.GetType().GetProperty(binder.Name);
if (property == null)
{
result = null;
return false;
}
result = property.GetValue(_resultObject, null);
return true;
}
}
Usage, assuming the following controller:
public class FooController : Controller
{
public IActionResult Get()
{
return Json(new {Bar = "Bar", Baz = "Baz"});
}
}
The test (xUnit):
// Arrange
var controller = new FoosController();
// Act
var result = await controller.Get();
// Assert
var resultObject = Assert.IsType<JsonResult>(result);
dynamic resultData = new JsonResultDynamicWrapper(resultObject);
Assert.Equal("Bar", resultData.Bar);
Assert.Equal("Baz", resultData.Baz);