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

geo*_*rtz 6 c# asp.net-mvc unit-testing

使用带有期望 json 帖子的方法的控制器,例如...

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

当您尝试测试时,如何设置单元测试以将发布数据发送到控制器?

Nko*_*osi 7

要传递数据,您可以使用模拟的 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

不要重新发明轮子。

MVC 框架已经提供了用于解释发送到控制器操作(Cross-cutting 关注点)的数据的功能。这样您就不必担心必须为要使用的模型补水。该框架将为您完成。它将使您的控制器操作更清晰,更易于管理和维护。

如果可能,您应该考虑将强类型数据发送到您的操作。

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

该框架基本上将通过使用其 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.
    }
}
Run Code Online (Sandbox Code Playgroud)