NOTE: This post is based on an older preview version of ASP.NET MVC and details have very likely CHANGED. Go to http://www.asp.net/mvc or http://www.asp.net/forums for updated details and the latest version of ASP.NET MVC.
All the sessions from Mix are up on http://sessions.visitmix.com/ for your viewing pleasure. I had a total blast giving the ASP.NET MVC Talk. The energy was really good and the crowd (of around 600, I hear) was really cool.
You can download the MVC talk in these formats:
I think the sound is a little quiet, so I had to turn it up some. It's better turned up a bit so you can hear the interaction with the crowd.
Here's some of the code from the talk you might be interested in. I'll post the rest very soon.
The first are the MVCMockHelpers used in the Test Driven Development part of the talk, and also in the 4th ASP.NET MVC Testing Video up at www.asp.net/mvc.
NOTE AND DISCLAIMER: This is just a little chunks of helper methods, and I happened to use Rhino Mocks, an Open Source Mocking Framework, the talk at Mix. At my last company I introduced TypeMock and we bought it and lately I've been digging on Moq also. I'm not qualified yet to have a dogmatic opinion about which one is better, because they all do similar things. Use the one that makes you happy. I hope to see folks (that's YOU Dear Reader) repost and rewrite these helpers (and better, more complete ones) using all the different mocking tools. Don't consider this to be any kind of "stamp of approval" for one mocking framework over another. Cool?
Anyway, here's the mocking stuff I used in the demo. This is similar to the stuff PhilHa did last year but slightly more complete. Still, this is just the beginning. We'll be hopefully releasing ASP.NET MVC bits on CodePlex maybe monthly. The goal is to release early and often. Eilon and the team have a lot more planned around testing, so remember, this is Preview 2 not Preview 18.
using System; using System.Web; using Rhino.Mocks; using System.Text.RegularExpressions; using System.IO; using System.Collections.Specialized; using System.Web.Mvc; using System.Web.Routing; namespace UnitTests { public static class MvcMockHelpers { public static HttpContextBase FakeHttpContext(this MockRepository mocks) { HttpContextBase context = mocks.PartialMock<httpcontextbase>(); HttpRequestBase request = mocks.PartialMock<httprequestbase>(); HttpResponseBase response = mocks.PartialMock<httpresponsebase>(); HttpSessionStateBase session = mocks.PartialMock<httpsessionstatebase>(); HttpServerUtilityBase server = mocks.PartialMock<httpserverutilitybase>(); SetupResult.For(context.Request).Return(request); SetupResult.For(context.Response).Return(response); SetupResult.For(context.Session).Return(session); SetupResult.For(context.Server).Return(server); mocks.Replay(context); return context; } public static HttpContextBase FakeHttpContext(this MockRepository mocks, string url) { HttpContextBase context = FakeHttpContext(mocks); context.Request.SetupRequestUrl(url); return context; } public static void SetFakeControllerContext(this MockRepository mocks, Controller controller) { var httpContext = mocks.FakeHttpContext(); ControllerContext context = new ControllerContext(new RequestContext(httpContext, new RouteData()), controller); controller.ControllerContext = context; } static string GetUrlFileName(string url) { if (url.Contains("?")) return url.Substring(0, url.IndexOf("?")); else return url; } static NameValueCollection GetQueryStringParameters(string url) { if (url.Contains("?")) { NameValueCollection parameters = new NameValueCollection(); string[] parts = url.Split("?".ToCharArray()); string[] keys = parts[1].Split("&".ToCharArray()); foreach (string key in keys) { string[] part = key.Split("=".ToCharArray()); parameters.Add(part[0], part[1]); } return parameters; } else { return null; } } public static void SetHttpMethodResult(this HttpRequestBase request, string httpMethod) { SetupResult.For(request.HttpMethod).Return(httpMethod); } public static void SetupRequestUrl(this HttpRequestBase request, string url) { if (url == null) throw new ArgumentNullException("url"); if (!url.StartsWith("~/")) throw new ArgumentException("Sorry, we expect a virtual url starting with \"~/\"."); SetupResult.For(request.QueryString).Return(GetQueryStringParameters(url)); SetupResult.For(request.AppRelativeCurrentExecutionFilePath).Return(GetUrlFileName(url)); SetupResult.For(request.PathInfo).Return(string.Empty); } } }
Here's the same thing in Moq. Muchas gracias, Kzu.
using System; using System.Web; using System.Text.RegularExpressions; using System.IO; using System.Collections.Specialized; using System.Web.Mvc; using System.Web.Routing; using Moq; namespace UnitTests { public static class MvcMockHelpers { 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>(); context.Expect(ctx => ctx.Request).Returns(request.Object); context.Expect(ctx => ctx.Response).Returns(response.Object); context.Expect(ctx => ctx.Session).Returns(session.Object); context.Expect(ctx => ctx.Server).Returns(server.Object); return context.Object; } public static HttpContextBase FakeHttpContext(string url) { HttpContextBase context = FakeHttpContext(); context.Request.SetupRequestUrl(url); return context; } public static void SetFakeControllerContext(this Controller controller) { var httpContext = FakeHttpContext(); ControllerContext context = new ControllerContext(new RequestContext(httpContext, new RouteData()), controller); controller.ControllerContext = context; } static string GetUrlFileName(string url) { if (url.Contains("?")) return url.Substring(0, url.IndexOf("?")); else return url; } static NameValueCollection GetQueryStringParameters(string url) { if (url.Contains("?")) { NameValueCollection parameters = new NameValueCollection(); string[] parts = url.Split("?".ToCharArray()); string[] keys = parts[1].Split("&".ToCharArray()); foreach (string key in keys) { string[] part = key.Split("=".ToCharArray()); parameters.Add(part[0], part[1]); } return parameters; } else { return null; } } public static void SetHttpMethodResult(this HttpRequestBase request, string httpMethod) { Mock.Get(request) .Expect(req => req.HttpMethod) .Returns(httpMethod); } public static void SetupRequestUrl(this HttpRequestBase request, string url) { if (url == null) throw new ArgumentNullException("url"); if (!url.StartsWith("~/")) throw new ArgumentException("Sorry, we expect a virtual url starting with \"~/\"."); var mock = Mock.Get(request); mock.Expect(req => req.QueryString) .Returns(GetQueryStringParameters(url)); mock.Expect(req => req.AppRelativeCurrentExecutionFilePath) .Returns(GetUrlFileName(url)); mock.Expect(req => req.PathInfo) .Returns(string.Empty); } } }
Maybe RoyO will do the same thing in TypeMock in the next few hours and I'll copy/paste it here. ;)
Thanks to Roy at TypeMock.
using System; using System.Collections.Specialized; using System.Web; using System.Web.Mvc; using System.Web.Routing; using TypeMock; namespace Typemock.Mvc { static class MvcMockHelpers { public static void SetFakeContextOn(Controller controller) { HttpContextBase context = MvcMockHelpers.FakeHttpContext(); controller.ControllerContext = new ControllerContext(new RequestContext(context, new RouteData()), controller); } public static void SetHttpMethodResult(this HttpRequestBase request, string httpMethod) { using (var r = new RecordExpectations()) { r.ExpectAndReturn(request.HttpMethod, httpMethod); } } public static void SetupRequestUrl(this HttpRequestBase request, string url) { if (url == null) throw new ArgumentNullException("url"); if (!url.StartsWith("~/")) throw new ArgumentException("Sorry, we expect a virtual url starting with \"~/\"."); var parameters = GetQueryStringParameters(url); var fileName = GetUrlFileName(url); using (var r = new RecordExpectations()) { r.ExpectAndReturn(request.QueryString, parameters); r.ExpectAndReturn(request.AppRelativeCurrentExecutionFilePath, fileName); r.ExpectAndReturn(request.PathInfo, string.Empty); } } static string GetUrlFileName(string url) { if (url.Contains("?")) return url.Substring(0, url.IndexOf("?")); else return url; } static NameValueCollection GetQueryStringParameters(string url) { if (url.Contains("?")) { NameValueCollection parameters = new NameValueCollection(); string[] parts = url.Split("?".ToCharArray()); string[] keys = parts[1].Split("&".ToCharArray()); foreach (string key in keys) { string[] part = key.Split("=".ToCharArray()); parameters.Add(part[0], part[1]); } return parameters; } else { return null; } } public static HttpContextBase FakeHttpContext(string url) { HttpContextBase context = FakeHttpContext(); context.Request.SetupRequestUrl(url); return context; } public static HttpContextBase FakeHttpContext() { HttpContextBase context = MockManager.MockObject<HttpContextBase>().Object; HttpRequestBase request = MockManager.MockObject<HttpRequestBase>().Object; HttpResponseBase response = MockManager.MockObject<HttpResponseBase>().Object; HttpSessionStateBase sessionState = MockManager.MockObject<HttpSessionStateBase>().Object; HttpServerUtilityBase serverUtility = MockManager.MockObject<HttpServerUtilityBase>().Object; using (var r = new RecordExpectations()) { r.DefaultBehavior.RepeatAlways(); r.ExpectAndReturn(context.Response, response); r.ExpectAndReturn(context.Request, request); r.ExpectAndReturn(context.Session, sessionState); r.ExpectAndReturn(context.Server, serverUtility); } return context; } } }
It was a great presentation. There's one thing I'm still unclear on, though. Is MVC replacing Web Forms?
Add an HtmlHelper method for a simple TableRow: this would be sure to assign the property names automatically to facilitate the use of UpdateFrom().
Scott Hanselman's Productivity Tips Video
Scott at DevReach in Bulgaria in October
Developer Stand up Comedy - Coding 4 Fun
TechDays/DevDays Netherlands and Belgium:
Posts by Category Posts by Month
Greatest Hits Dev Tools List