How to Unit-Test a JSON Controller

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));

How to unit-test a JSON controller?

Just like people commented above, this would be a functional test.

The best way would probably be making a request, parsing the JSON response body, and matching it to the expected result.

If I have companies_controller in Rspec using FactoryGirl:

describe "GET 'show'" do

before(:each) do
@company = Factory(:company)
get 'show', :format => :json, :id => @company.id
end

it "should be successful" do
response.should be_success
end

it "should return the correct company when correct id is passed" do
body = JSON.parse(response.body)
body["id"].should == @company.id
end

end

You can test other attributes the same way. Also, I normally have invalid context where I would try to pass invalid parameters.

how to create json post in unit test to mvc controller

To pass the data you can set the controller context with a mocked http context and pass a fake stream of the request body.

Used moq to fake the request.

[TestClass]
public class MyControllerTests {
[TestMethod]
public void PostAction_Should_Receive_Json_Data() {
//Arrange

//create a fake stream of data to represent request body
var json = "{ \"Key\": \"Value\"}";
var bytes = System.Text.Encoding.UTF8.GetBytes(json.ToCharArray());
var stream = new MemoryStream(bytes);

//create a fake http context to represent the request
var mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.Setup(m => m.Request.InputStream).Returns(stream);

var sut = new MyController();
//Set the controller context to simulate what the framework populates during a request
sut.ControllerContext = new ControllerContext {
Controller = sut,
HttpContext = mockHttpContext.Object
};

//Act
var result = sut.PostAction() as ViewResult;

//Assert
Assert.AreEqual(json, result.Model);
}

public class MyController : Controller {
[HttpPost]
public ActionResult PostAction() {
string json = new StreamReader(Request.InputStream).ReadToEnd();
//do something with json
//returning json as model just to prove it received the data
return View((object)json);
}
}
}

With that out of the way, now some advice.

Don't reinvent the wheel.

The MVC framework already provides the functionality for interpreting data sent to controller action (Cross-cutting concerns). That way you don't have to worry yourself with having to hydrate a model to work with. The framework will do it for you. It will make your controller actions cleaner and easier to manage and maintain.

You should consider sending strongly typed data to your actions if possible.

public class MyController : Controller {
[HttpPost]
public ActionResult PostAction(MyModel model) {
//do something with model
}
}

The framework will basically do exactly what you are doing manually in your action by doing what is called parameter binding using its ModelBinder. It will deserialize the body of the request and bind properties of the incoming data to the action parameter if they match.

With that it also allows for easier unit testing of your controllers

[TestClass]
public class MyControllerTests {
[TestMethod]
public void PostAction_Should_Receive_Json_Data() {
//Arrange

var model = new MyModel {
Key = "Value"
};

var sut = new MyController();

//Act
var result = sut.PostAction(model);

//Assert
//...assertions here.
}
}

How to get data in JSON format from a controller returning IHttpActionResult in C#?

I found the answer -

IHttpActionResult keeps the SerializerSettings stored which might be applied down the pipeline when the response is disposed off.

In the unit test, since we are taking data from controller i.e. in middle of the pipeline, we will have to apply SerializerSettings ourselves.
So, first step is the extract the IEnumerable from action result -

IHttpActionResult actionResult = MockController.Get();
JsonResult<IEnumerable<Product>> contentResult = actionResult as JsonResult<IEnumerable<Product>>;

And then, apply the serializer settings and get your json -

string responseString = JsonConvert.SerializeObject(contentResult.Content, contentResult.SerializerSettings);
JArray responseJson = JArray.Parse(responseString);

Hope, this would help others.

How to Unit Test JsonResult and Collections in MSTest

You should be able to test this just like anything else, provided you can extract the values from the JsonResult. Here's a helper that will do that for you:

private T GetValueFromJsonResult<T>(JsonResult jsonResult, string propertyName)
{
var property =
jsonResult.Data.GetType().GetProperties()
.Where(p => string.Compare(p.Name, propertyName) == 0)
.FirstOrDefault();

if (null == property)
throw new ArgumentException("propertyName not found", "propertyName");
return (T)property.GetValue(jsonResult.Data, null);
}

Then call your controller as usual, and test the result using that helper.

var jsonResult = yourController.YourAction(params);
bool testValue = GetValueFromJsonResult<bool>(jsonResult, "PropertyName");
Assert.IsFalse(testValue);

How to test JsonResult from .NET MVC controller

I have to give credit to this post first: How do I iterate over the properties of an anonymous object in C#?

var result = new JsonResult{ Data = new {details = "This location has not entered any comments or further details for this event."}};

var det = result.Data.GetType().GetProperty("details", BindingFlags.Instance | BindingFlags.Public);

var dataVal = det.GetValue(result.Data, null);

Hope this helps or at least gives you a jumping point.

Test JSON-returning controller method without MissingViewError

You aren't issuing a JSON request/accessing a JSON endpoint, as neither your request URL does contain the .json extension, nor does your request send an appropriate Accept header (I don't remember whether the latter is possible with the 2.x controller test case class at all).

Use the .json extension and you should be good.

$this->testAction('/people/mapLeads/' . $id . '.json', array('return' => 'vars'));


Related Topics



Leave a reply



Submit