MVC 3 Unit Test - Get Actual Response Data

守給你的承諾、 提交于 2019-12-25 01:38:41

问题


All,

I'm developing and unit testing an interactive voice application using ASP.NET MVC 3 whose controllers return Views containing VoiceXML. I'd like to create unit tests that capture the actual VoiceXML output so I can schema-validate it.

My reading and testing have taken me to Scott H's FakeHttpContext that uses Moq, as well as several responses here. Everything compiles correctly, and I'm trying to do something like the following:

[TestMethod]
public void WelcomeTest1()
{
     EmergencyController controller = new EmergencyController();
     controller.ControllerContext = new  ControllerContext(MvcMockHelpers.FakeHttpContext("~/Emergency/Welcome"), new RouteData(), controller);

     ViewResult result = (controller.Welcome()) as ViewResult;
 .
 .
     Assert.IsTrue(controller.ControllerContext.HttpContext.Response.OutputStream.Length > 0);
     // assert schema validation on the output here
}

However, stepping through this, I can see that the Welcome view being called, but I'm looking for something in the Response.Output and not finding anything. The mock is set up as follows, in hope that setting CallBase to true would actually write something out. I found some code that I added to the FakeHttpContext constructor that supposedly invokes a StringWriter, but to no avail:

public static HttpContextBase FakeHttpContext()
{
    var context = new Mock<HttpContextBase>();
    var request = new Mock<HttpRequestBase>() { CallBase = true };
    var response = new Mock<HttpResponseBase>();
    var session = new Mock<HttpSessionStateBase>();
    var server = new Mock<HttpServerUtilityBase>();

    context.Setup(ctx => ctx.Request).Returns(request.Object);
    context.Setup(ctx => ctx.Response).Returns(response.Object);
    context.Setup(ctx => ctx.Session).Returns(session.Object);
    context.Setup(ctx => ctx.Server).Returns(server.Object);
    response.Setup(r => r.OutputStream).Returns(new MemoryStream());
    response.Setup(r => r.Headers).Returns(new NameValueCollection());           

    var writer = new StringWriter();
    var wr = new SimpleWorkerRequest("", "", "", "", writer);        
    HttpContext.Current = new HttpContext(wr);

    return context.Object;
}

I'm sure I'm missing something obvious, but I'm stumped right now.

Thanks

Jim Stanley

Blackboard Connect


回答1:


The result doesn't get populated in the ViewResult. In other words, the view isn't rendered by you calling return View() in your controller, rather mvc takes the viewresult and renders it at a later time in the request-sycle. What you need to do is to create a render-function for ViewResults, like this one:

using System;
using System.IO;
using System.Web.Mvc;

namespace CoPrice.Helpers
{
    public static class ViewRendrer
    {
        public static string ToHtml(this ViewResult result, Controller controller)
        {
            controller.ViewData.Model = result.Model;
            try
            {
                using (StringWriter sw = new StringWriter())
                {
                    ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, result.ViewName);
                    ViewContext context = new ViewContext(controller.ControllerContext, viewResult.View, result.ViewData, result.TempData, sw);
                    viewResult.View.Render(context, sw);

                    return sw.GetStringBuilder().ToString();
                }
            }
            catch (Exception e)
            {
                return e.ToString();
            }
        }
    }
}

Then you can do result.ToHtml(controller) to get the actual data (this works for RazorViews only I think, though I'm not sure, that's what I've used it for at least).



来源:https://stackoverflow.com/questions/5982659/mvc-3-unit-test-get-actual-response-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!