Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to create json post in unit test to mvc controller

With a controller with a method that is expecting a json post such as...

public class MyController : Controller
{
    [HttpPost]
    public ActionResult PostAction()
    {
        string json = new StreamReader(Request.InputStream).ReadToEnd();
        //do something with json
    }
}

how do you set up a unit test to send the post data to the controller when you're trying to test it?

like image 797
geoff swartz Avatar asked Oct 07 '16 00:10

geoff swartz


People also ask

How pass JSON data in MVC?

Make sure you specify POST type, as ajax method uses GET method by default. MVC Controller: Decorate the Action method with HttpPost verb. This action method will only handle http post request from browser. Ajax submission from the browser will be automatically deserialized to FormData c# class as a poco.

Can we directly return JSON in MVC?

In this article I will explain with an example, how to use the JsonResult class object for returning JSON data from Controller to View in ASP.Net MVC. The Controller Action method will be called using jQuery POST function and JSON data will be returned back to the View using JsonResult class object.

What is JSON in MVC with example?

JSON Java Script Object Notation is a very familiar and commonly used concept. It is a data interchange medium and is very lightweight. It is one kind of syntax for storing and passing data. Since it is Javascript object notation, it uses the javascript style of syntax, but actually is text only.


1 Answers

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.
    }
}
like image 193
Nkosi Avatar answered Sep 28 '22 00:09

Nkosi