如何在单元测试中创建json post到MVC控制器

本文关键字:post MVC 控制器 json 创建 单元测试 | 更新日期: 2023-09-27 18:12:08

有一个方法的控制器,它期望一个json post,如…

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

你如何设置一个单元测试发送post数据到控制器,当你试图测试它?

如何在单元测试中创建json post到MVC控制器

要传递数据,您可以使用模拟的http上下文设置控制器上下文,并传递请求体的假流。

使用moq来接收请求。

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

有了这些,现在有一些建议。

不要重新发明轮子。

MVC框架已经提供了解释发送给控制器动作的数据的功能(横切关注点)。这样你就不用担心要给模型补水了。框架将为您完成这些工作。它将使你的控制器动作更干净,更容易管理和维护。

如果可能的话,你应该考虑发送强类型的数据给你的操作。

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

框架基本上会通过使用ModelBinder进行所谓的参数绑定来完成您在操作中手动执行的操作。它将对请求体进行反序列化,并在匹配的情况下将传入数据的属性绑定到动作参数。

它也允许更容易的单元测试你的控制器

[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.
    }
}

您对HttpGetHttpPost的控制器操作执行单元测试的方式相同。

[Test]
public void Test_MyController_PostAction()
{
    var controller = new MyController();
    ActionResult result = controller.PostAction();
    // Assert here
}

假设你的动作需要一个模型参数。

[Test]
public void Test_MyController_PostAction()
{
    var controller = new MyController();
    ActionResult result = controller.PostAction(new SomeModel()); // Just pass as parameter
    // Assert here
}