What is the best way to Unit Test the string response and content type from several Controller methods?
Each method returns an ActionResult
, some of which are ViewResult
responses. I'm using ASP.NET MVC 2 RTM and Moq.
I wish to obtain the TextWriter
from HttpContext.Response
and have it contain the full string response from an ActionResult
.
I want to test some specific if content does and does not exist with the output.
I use a background worker thread to update static content on remote servers, this content is the output from the Controllers and must be generated as such. Making requests to the same server via HTTP is not advisable because there are many 1000's of files which are updated.
I see the same code being used at both Runtime and via Unit Tests, as it would be very similar?
How to correctly setup mocking to not require Routes Or call RegisterRoutes
and RegisterAllAreas
have the call succeed, currently throws an exception deep inside BuildManagerWrapper::IBuildManager.GetReferencedAssemblies
.
public static HttpContextBase FakeHttpContext()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();
var writer = new StringWriter();
var form = new NameValueCollection();
var queryString = new NameValueCollection();
request.Setup(r => r.Form).Returns(form);
request.Setup(r => r.QueryString).Returns(queryString);
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);
context.Setup(ctx => ctx.Response.Output).Returns(writer);
return context.Object;
}
public static void SetFakeControllerContext(this Controller controller)
{
var httpContext = FakeHttpContext();
var routeData = new RouteData();
var routeData = RouteTable.Routes.GetRouteData(httpContext);
ControllerContext context = new ControllerContext(new RequestContext(httpContext, routeData), controller);
controller.ControllerContext = context;
}
[TestMethod]
public void CodedJavaScriptAction_Should_Return_JavaScript_Response()
{
// Arrange
var controller = new CodedController();
controller.SetFakeControllerContext();
// Act
var result = controller.CodedJavaScript(); // Response is made up as a ViewResult containing JavaScript.
var controllerContext = controller.ControllerContext;
var routeData = controllerContext.RouteData;
routeData.DataTokens.Add("area", "Coded");
routeData.Values.Add("area", "Coded");
routeData.Values.Add("controller", "Coded");
routeData.Values.Add("action", "CodedJavaScript");
var response = controllerContext.HttpContext.Response;
response.Buffer = true;
var vr = result as ViewResult;
vr.MasterName = "CodedJavaScript";
result.ExecuteResult(controllerContext);
// Assert
var s = response.Output.ToString();
Assert.AreEqual("text/javascript", response.ContentType);
Assert.IsTrue(s.Length > 0);
// @todo: Further tests to be added here.
}
-Areas\Coded\Controllers\CodeController.cs
-Areas\Coded\Views\Coded\CodedJavaScript.aspx
-Areas\Coded\CodedAreaRegistration.cs
-Views\Shared\CodedJavaScript.Master
EDIT: edited to now include both Unit Testing and Runtime execution. Thanks to @Darin Dimitrov for mentioning Integration Testing but there is now also a runtime element to this question.
EDIT: After some testing and review using some of the source code from MvcIntegrationTestFramework as referenced by alexn. Which uses AppDomain.CreateDomain
and SimpleWorkerRequest
to create a new request, I have found that it is not possible to create a new request via this method in a process that already has an active request, due to static
values used. So this rules this method out.
Probably the same issue but I am now wondering if the result from a Partial View can be returned as a string more directly?
When you set Action's return type ActionResult , you can return any subtype of it e.g Json,PartialView,View,RedirectToAction.
If you've writing custom filters, routes, etc, you should unit test them, but not as part of your tests on a particular controller action. They should be tested in isolation.
Writing a Unit Test for REST Controller First, we need to create Abstract class file used to create web application context by using MockMvc and define the mapToJson() and mapFromJson() methods to convert the Java object into JSON string and convert the JSON string into Java object.
What you are trying to achieve is no longer unit tests but integration testing because you are no longer testing your application components in isolation and there are great tools that allow you to do this like Selenium or Web Tests in the Ultimate versions of Visual Studio.
The advantage of these tests is that they simulate user requests and cover the entire application behavior. So for a given user request you can assert that your application responds properly. The idea is that you write user scenarios, record them and then you could automate the execution of those tests to assert that your application responds as specified.
I use Steven Sandersons MvcIntegrationTestFramework with great success. It's very easy to use.
With this, you can easily test output response, viewdata, cookies, session and a lot more with very little effort.
You would test the rendered HTML with a test looking something like this:
[Test]
public void Output_Contains_String()
{
appHost.SimulateBrowsingSession(session => {
var result = session.ProcessRequest("/");
Assert.IsTrue(result.ResponseText.Contains("string to check for"));
});
}
No mocking and routes registering. Very clean.
As this is technically an integration test, it will take some time to set up and run.
Please let me know if you need any more examples or some more information.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With