ASP.NET MVC: Using dynamic type to test controller actions returning JsonResult
Join the DZone community and get the full member experience.Join For Free
I wrote unit tests for my ASP.NET MVC application that uses some jQuery AJAX-components. These components load data from server in JSON format. I needed to write tests for these methods to make sure that correct data is returned to client. In this posting I will show you how to use dynamic type to test JSON-based action results and therefore avoid creating DTO classes.
Example of controller action
To keep the code compact for reading I represent my controller action as one method without any fragmentation.
public JsonResult ListCompanyRepresentatives(int id)
var party = _partyRepository.GetCompanyById(id);
var names = from n in party.Representatives
orderby n.ValidTo, n.RepresentativeParty.DisplayName
Id = n.Id.ToString(),
Name = n.RepresentativeParty.DisplayName,
Role = n.Role ?? string.Empty,
Context = n.Context ?? string.Empty,
ValidFrom = n.ValidFrom.ToShortDateString(),
ValidTo = n.ValidTo.ToShortDateString()
var rows = names.ToArray();
var data = new
total = rows.Count(),
page = 1,
records = rows.Count(),
rows = rows
return Json(data, JsonRequestBehavior.AllowGet);
You see here two anonymous types. One of them is created for party representatives and the other one is data structure for JSON-based result. JSON-based result contains array of party representatives. End the end we have one anonymous type that is hosting array of another anonymous type objects. The question is how to write tests for the end result?
Problems with anonymous types
You can say that we can create one DTO class for type returned as array and the other DTO class (or maybe generic class) for JSON results. This would be easy solution but it may end up with large number of DTO classes. This is why I try to get work done with anonymous types.
Anonymous types are not very good to test because they are declared as internal. As we know types in internal scope are visible only to other classes in same assembly. Test are usually located in separate project and separate assembly and by default they don’t see those anonymous types.
There is one problem more. Take a look at the code in test that reads data from JSON result.
var result = _controller.ListCompanyNames(company.Id) as JsonResult;
var data = result.Data;
Data returns us object. To read properties we need to the type of object. The type is anonymous and we cannot cast to anonymous type. We can use reflection but for me it is not good solution because reflection may cause some overhead in performance and if we have many tests then reflection may slow down test runs.
Solution – using dynamic type
Here is the fragment of test that uses dynamics.
dynamic data = result.Data;
dynamic companyName = data.rows;
var name = company.Names;
When we run tests we get errors that object has no property called rows. Well, that’s because anonymous types are internal. We have to make them visible to our tests library.
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.
This line tells .NET Framework that internal types of our ASP.NET MVC project must be visible to our tests project. If you have more than one tests library for your ASP.NET MVC application you can make web application internals visible to these libraries exactly the same way. Now you can run your tests and everything should work fine.
Using anonymous types with JSON results may be painful. For previous versions of .NET there are some other solutions to consider: using DTO-s, string comparison or reflection to test JSON results. In .NET 4.0 we can use dynamic type and avoid possible problems related to string comparison (by example, order of properties changes) and reflection (messy code and possible performance overhead). For us dynamic was excellent solution here. This way you can test also other AJAX-based responses that use anonymous types.
Published at DZone with permission of Gunnar Peipman, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.