<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://weblogs.asp.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Eilon Lipton&amp;#39;s Blog : unit test</title><link>http://weblogs.asp.net/leftslipper/archive/tags/unit+test/default.aspx</link><description>Tags: unit test</description><dc:language>en</dc:language><generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator><item><title>MVC: Unit testing controller actions that use TempData</title><link>http://weblogs.asp.net/leftslipper/archive/2008/04/13/mvc-unit-testing-controller-actions-that-use-tempdata.aspx</link><pubDate>Mon, 14 Apr 2008 04:00:52 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6095674</guid><dc:creator>Eilon</dc:creator><slash:comments>11</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=6095674</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2008/04/13/mvc-unit-testing-controller-actions-that-use-tempdata.aspx#comments</comments><description>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;Part of the &amp;quot;big deal&amp;quot; about &lt;a href="http://www.asp.net/mvc"&gt;ASP.NET MVC&lt;/a&gt;, and of course MVC in general, is that the code you write is more easily unit tested as compared to traditional ASP.NET WebForms. However, if you've used ASP.NET MVC and tried to write a unit test for a controller action that uses TempData, you probably got some exceptions about null references and other crazy stuff. I've seen a number of solutions out there that involve private reflection (which is kind of evil) so I figured I'd show how it can be done without that trickery. (Kudos, though, to those of you who figured out how to do such trickery!)&lt;/p&gt;  &lt;p&gt;The underlying problem is that the TempDataDictionary object tries to read from session state when it's first used. At unit test time ASP.NET is not running so there isn't any session state. The solution is to provide a mock session state object to the TempDataDictionary. We're basically telling TempDataDictionary, &amp;quot;Hey you want some session state??? Here's your session state!!!&amp;quot;&lt;/p&gt;  &lt;p&gt;The controller we're going to test has two actions. The first action adds a value to TempData and then does a redirect. The second action checks for the existence of the value in TempData and renders a view.&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HomeController &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;Controller &lt;/span&gt;{
    &lt;span style="color: blue"&gt;public void &lt;/span&gt;Index() {
        &lt;span style="color: green"&gt;// Save UserID into TempData and redirect to greeting page
        &lt;/span&gt;TempData[&lt;span style="color: #a31515"&gt;&amp;quot;UserID&amp;quot;&lt;/span&gt;] = &lt;span style="color: #a31515"&gt;&amp;quot;user123&amp;quot;&lt;/span&gt;;
        RedirectToAction(&lt;span style="color: #a31515"&gt;&amp;quot;GreetUser&amp;quot;&lt;/span&gt;);
    }

    &lt;span style="color: blue"&gt;public void &lt;/span&gt;GreetUser() {
        &lt;span style="color: green"&gt;// Check that the UserID is present. If it's not
        // there, redirect to error page. If it is, show
        // the greet user view.
        &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;(!TempData.ContainsKey(&lt;span style="color: #a31515"&gt;&amp;quot;UserID&amp;quot;&lt;/span&gt;)) {
            RedirectToAction(&lt;span style="color: #a31515"&gt;&amp;quot;ErrorPage&amp;quot;&lt;/span&gt;);
            &lt;span style="color: blue"&gt;return&lt;/span&gt;;
        }
        ViewData[&lt;span style="color: #a31515"&gt;&amp;quot;NewUserID&amp;quot;&lt;/span&gt;] = TempData[&lt;span style="color: #a31515"&gt;&amp;quot;UserID&amp;quot;&lt;/span&gt;];
        RenderView(&lt;span style="color: #a31515"&gt;&amp;quot;GreetUser&amp;quot;&lt;/span&gt;);
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;In order to write the unit tests I created a mock HttpContext with a mock session state object:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// HttpContext for TempData that uses a custom
// session object.
&lt;/span&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpContext &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;HttpContextBase &lt;/span&gt;{
    &lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpSessionState &lt;/span&gt;_sessionState =
        &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpSessionState&lt;/span&gt;();

    &lt;span style="color: blue"&gt;public override &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HttpSessionStateBase &lt;/span&gt;Session {
        &lt;span style="color: blue"&gt;get &lt;/span&gt;{
            &lt;span style="color: blue"&gt;return &lt;/span&gt;_sessionState;
        }
    }
}

&lt;span style="color: green"&gt;// HttpSessionState for TempData that uses a custom
// session object.
&lt;/span&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpSessionState &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;HttpSessionStateBase &lt;/span&gt;{
    &lt;span style="color: green"&gt;// This string is &amp;quot;borrowed&amp;quot; from the ASP.NET MVC source code
    &lt;/span&gt;&lt;span style="color: blue"&gt;private string &lt;/span&gt;TempDataSessionStateKey = &lt;span style="color: #a31515"&gt;&amp;quot;__ControllerTempData&amp;quot;&lt;/span&gt;;
    &lt;span style="color: blue"&gt;private object &lt;/span&gt;_tempDataObject;

    &lt;span style="color: blue"&gt;public override object this&lt;/span&gt;[&lt;span style="color: blue"&gt;string &lt;/span&gt;name] {
        &lt;span style="color: blue"&gt;get &lt;/span&gt;{
            &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;(
                TempDataSessionStateKey,
                name,
                &lt;span style="color: #a31515"&gt;&amp;quot;Wrong session key used&amp;quot;&lt;/span&gt;);
            &lt;span style="color: blue"&gt;return &lt;/span&gt;_tempDataObject;
        }
        &lt;span style="color: blue"&gt;set &lt;/span&gt;{
            &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;(
                TempDataSessionStateKey,
                name,
                &lt;span style="color: #a31515"&gt;&amp;quot;Wrong session key used&amp;quot;&lt;/span&gt;);
            _tempDataObject = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
        }
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;Each unit test that involves an action that uses TempData needs to create a custom TestTempDataHttpContext object and use that in a new instance of TempDataDictionary:

&lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpContext &lt;/span&gt;tempDataHttpContext = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpContext&lt;/span&gt;();
homeController.TempData = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TempDataDictionary&lt;/span&gt;(tempDataHttpContext);&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;I wrote three unit tests for HomeController:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Test that the Index action sets the right TempData and does a redirect&lt;/li&gt;

  &lt;li&gt;Test that the GreetUser action redirects when the TempData is missing the value&lt;/li&gt;

  &lt;li&gt;Test that the GreetUser action renders the GreetUser view with the right ViewData when the TempData has the right value&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And here are the unit tests:&lt;/p&gt;

&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;TestClass&lt;/span&gt;]
&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HomeControllerTest &lt;/span&gt;{
    [&lt;span style="color: #2b91af"&gt;TestMethod&lt;/span&gt;]
    &lt;span style="color: blue"&gt;public void &lt;/span&gt;IndexSavesUserIDToTempDataAndRedirects() {
        &lt;span style="color: green"&gt;// Setup
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestHomeController &lt;/span&gt;homeController = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestHomeController&lt;/span&gt;();
        &lt;span style="color: #2b91af"&gt;TestTempDataHttpContext &lt;/span&gt;tempDataHttpContext = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpContext&lt;/span&gt;();
        homeController.TempData = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TempDataDictionary&lt;/span&gt;(tempDataHttpContext);

        &lt;span style="color: green"&gt;// Execute
        &lt;/span&gt;homeController.Index();

        &lt;span style="color: green"&gt;// Verify
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.IsTrue(homeController.RedirectValues.ContainsKey(&lt;span style="color: #a31515"&gt;&amp;quot;action&amp;quot;&lt;/span&gt;));
        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual(&lt;span style="color: #a31515"&gt;&amp;quot;GreetUser&amp;quot;&lt;/span&gt;, homeController.RedirectValues[&lt;span style="color: #a31515"&gt;&amp;quot;action&amp;quot;&lt;/span&gt;]);

        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.IsTrue(homeController.TempData.ContainsKey(&lt;span style="color: #a31515"&gt;&amp;quot;UserID&amp;quot;&lt;/span&gt;));
        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual(&lt;span style="color: #a31515"&gt;&amp;quot;user123&amp;quot;&lt;/span&gt;, homeController.TempData[&lt;span style="color: #a31515"&gt;&amp;quot;UserID&amp;quot;&lt;/span&gt;]);
    }

    [&lt;span style="color: #2b91af"&gt;TestMethod&lt;/span&gt;]
    &lt;span style="color: blue"&gt;public void &lt;/span&gt;GreetUserWithNoUserIDRedirects() {
        &lt;span style="color: green"&gt;// Setup
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestHomeController &lt;/span&gt;homeController = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestHomeController&lt;/span&gt;();
        &lt;span style="color: #2b91af"&gt;TestTempDataHttpContext &lt;/span&gt;tempDataHttpContext = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpContext&lt;/span&gt;();
        homeController.TempData = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TempDataDictionary&lt;/span&gt;(tempDataHttpContext);

        &lt;span style="color: green"&gt;// Execute
        &lt;/span&gt;homeController.GreetUser();

        &lt;span style="color: green"&gt;// Verify
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.IsTrue(homeController.RedirectValues.ContainsKey(&lt;span style="color: #a31515"&gt;&amp;quot;action&amp;quot;&lt;/span&gt;));
        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual(&lt;span style="color: #a31515"&gt;&amp;quot;ErrorPage&amp;quot;&lt;/span&gt;, homeController.RedirectValues[&lt;span style="color: #a31515"&gt;&amp;quot;action&amp;quot;&lt;/span&gt;]);

        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual(0, homeController.TempData.Count);
    }

    [&lt;span style="color: #2b91af"&gt;TestMethod&lt;/span&gt;]
    &lt;span style="color: blue"&gt;public void &lt;/span&gt;GreetUserWithUserIDCopiesToViewDataAndRenders() {
        &lt;span style="color: green"&gt;// Setup
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestHomeController &lt;/span&gt;homeController = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestHomeController&lt;/span&gt;();
        &lt;span style="color: #2b91af"&gt;TestTempDataHttpContext &lt;/span&gt;tempDataHttpContext = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestTempDataHttpContext&lt;/span&gt;();
        homeController.TempData = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TempDataDictionary&lt;/span&gt;(tempDataHttpContext);
        homeController.TempData[&lt;span style="color: #a31515"&gt;&amp;quot;UserID&amp;quot;&lt;/span&gt;] = &lt;span style="color: #a31515"&gt;&amp;quot;TestUserID&amp;quot;&lt;/span&gt;;

        &lt;span style="color: green"&gt;// Execute
        &lt;/span&gt;homeController.GreetUser();

        &lt;span style="color: green"&gt;// Verify
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;(&lt;span style="color: #a31515"&gt;&amp;quot;GreetUser&amp;quot;&lt;/span&gt;, homeController.RenderViewName);
        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;(&lt;span style="color: #2b91af"&gt;String&lt;/span&gt;.Empty, homeController.RenderMasterName);
        &lt;span style="color: #2b91af"&gt;IDictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;object&lt;/span&gt;&amp;gt; viewData =
            homeController.RenderViewData &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IDictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;object&lt;/span&gt;&amp;gt;;
        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.IsNotNull(viewData);
        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.IsTrue(viewData.ContainsKey(&lt;span style="color: #a31515"&gt;&amp;quot;NewUserID&amp;quot;&lt;/span&gt;));
        &lt;span style="color: #2b91af"&gt;Assert&lt;/span&gt;.AreEqual(&lt;span style="color: #a31515"&gt;&amp;quot;TestUserID&amp;quot;&lt;/span&gt;, viewData[&lt;span style="color: #a31515"&gt;&amp;quot;NewUserID&amp;quot;&lt;/span&gt;]);
    }

    &lt;span style="color: green"&gt;// Test-specific subclass for HomeController. This won't be
    // needed in the next release of ASP.NET MVC.
    &lt;/span&gt;&lt;span style="color: blue"&gt;private sealed class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;TestHomeController &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;HomeController &lt;/span&gt;{
        &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RouteValueDictionary &lt;/span&gt;RedirectValues;
        &lt;span style="color: blue"&gt;public string &lt;/span&gt;RenderViewName;
        &lt;span style="color: blue"&gt;public string &lt;/span&gt;RenderMasterName;
        &lt;span style="color: blue"&gt;public object &lt;/span&gt;RenderViewData;

        &lt;span style="color: blue"&gt;protected override void &lt;/span&gt;RedirectToAction(&lt;span style="color: #2b91af"&gt;RouteValueDictionary &lt;/span&gt;values) {
            RedirectValues = values;
        }

        &lt;span style="color: blue"&gt;protected override void &lt;/span&gt;RenderView(&lt;span style="color: blue"&gt;string &lt;/span&gt;viewName, &lt;span style="color: blue"&gt;string &lt;/span&gt;masterName,
            &lt;span style="color: blue"&gt;object &lt;/span&gt;viewData) {
            RenderViewName = viewName;
            RenderMasterName = masterName;
            RenderViewData = viewData;
        }
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Some notes about the code:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For the unit tests I also needed to create a &lt;a href="http://haacked.com/archive/2007/12/06/test-specific-subclasses-vs-partial-mocks.aspx"&gt;test-specific subclass&lt;/a&gt; for HomeController called TestHomeController in order to capture the values of a call to RedirectToAction and RenderView. In the upcoming preview of ASP.NET MVC this class won't be needed due to some changes we've made.&lt;/li&gt;

  &lt;li&gt;Making TempData easier to unit test is on our list of improvements for a later preview of ASP.NET MVC. We realize it's a bit tricky right now, and we plan to make it much, much easier.&lt;/li&gt;

  &lt;li&gt;Instead of creating concrete classes for the custom HttpContext and session state objects you could use a mock object framework to dynamically generate those instances. I chose not to show that since it might detract from the purpose of the post. If you're already using a mock object framework such as &lt;a href="http://www.ayende.com/projects/rhino-mocks.aspx"&gt;RhinoMocks&lt;/a&gt; or &lt;a href="http://code.google.com/p/moq/"&gt;Moq&lt;/a&gt; it should be easy to modify the code to use those frameworks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you find this sample useful when you're writing your unit tests. If you have any other pain points in ASP.NET MVC please post a comment so we'll know about it.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6095674" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/unit+test/default.aspx">unit test</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/aspnetmvc/default.aspx">aspnetmvc</category></item><item><title>MVC: I'll need a little bit more context on that</title><link>http://weblogs.asp.net/leftslipper/archive/2008/02/18/mvc-context.aspx</link><pubDate>Tue, 19 Feb 2008 00:00:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:5816702</guid><dc:creator>Eilon</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=5816702</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2008/02/18/mvc-context.aspx#comments</comments><description>&lt;P&gt;&lt;A href="http://weblogs.asp.net/scottgu/archive/2008/02/12/asp-net-mvc-framework-road-map-update.aspx" mce_href="http://weblogs.asp.net/scottgu/archive/2008/02/12/asp-net-mvc-framework-road-map-update.aspx"&gt;ScottGu recently announced&lt;/A&gt; the plans for the next public preview of the ASP.NET MVC framework. For those who don't feel like clicking on links to other peoples' blog posts Scott's blog says it's being released at &lt;A class="" href="http://www.visitmix.com/" mce_href="http://www.visitmix.com/"&gt;MIX08&lt;/A&gt;, which is only a couple of weeks away. And yes, I will be there!&lt;/P&gt;
&lt;P&gt;My previous blog post talked in general about the &lt;A href="http://weblogs.asp.net/leftslipper/archive/2007/12/10/asp-net-mvc-design-philosophy.aspx" mce_href="http://weblogs.asp.net/leftslipper/archive/2007/12/10/asp-net-mvc-design-philosophy.aspx"&gt;design philosophy&lt;/A&gt; of the ASP.NET MVC framework. Today I'd like to talk specifically about context objects, how we use them in ASP.NET MVC, and why we like them. In the coming release of MVC there will be about seven context types throughout ASP.NET, URL routing, and MVC.&lt;/P&gt;
&lt;H2&gt;What is a Context Object?&lt;/H2&gt;
&lt;P&gt;A context object is exactly that: An object that gives another object some information about what's going on. Information such as what is the current request, what task is being performed, and sometimes even the ability the change what's going on.&lt;/P&gt;
&lt;H2&gt;Context in MVC&lt;/H2&gt;
&lt;P&gt;One context object many ASP.NET developers are already familiar with is &lt;A href="http://msdn2.microsoft.com/en-us/library/system.web.httpcontext.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/system.web.httpcontext.aspx"&gt;HttpContext&lt;/A&gt;. HttpContext gives you everything you need to know about the current request, who's making that request, and how to respond to the request. Of course, in MVC we decoupled the MVC framework from the test-unfriendly HttpContext by introducing an IHttpContext interface (which, by the way, is now an HttpContextBase abstract base class for future-proofing purposes).&lt;/P&gt;
&lt;P&gt;However, as the request gets processed we create and gather up additional information about what's going on. The first context we add is at the routing level: the RequestContext type. It adds just one piece of information, the RouteData, as well as including all previous context information, which is just the HttpContextBase.&lt;/P&gt;
&lt;P&gt;Once a route is selected and we determine that it is an MVC request, we're off to the controller. This is where the ControllerContext comes in to the picture. ControllerContext derives from RequestContext and adds the controller instance to it. We then have a ViewContext type, which adds information about the selected view, its view data, and some other items.&lt;/P&gt;
&lt;P&gt;One of the new features in the upcoming preview is action filters, and sure enough there are three filter context types as well.&lt;/P&gt;
&lt;P&gt;Since the context types derive from one another (except for HttpContextBase), you can often pass in whatever context type you have to call some method from a lower level. For example, in the view you get a ViewContext that you can pass into the URL routing methods.&lt;/P&gt;
&lt;H2&gt;What Can Context Do For You?&lt;/H2&gt;
&lt;P&gt;By passing around context objects we have no need for global state. Global state would be something like a static property or field that everyone can get to. One of the typical requirements of a unit test is that during their execution they do not consume global state nor do they alter global state. We give you the context object and it has everything you need to know. How do I know that it's everything you need to know? Quite simply, the context object is all &lt;EM&gt;we&lt;/EM&gt; know anyway, so we're just letting &lt;EM&gt;you&lt;/EM&gt; know about it as well.&lt;/P&gt;
&lt;P&gt;Since your code now makes its decisions and operates on a passed-in context object, your unit tests can produce fake contexts and pass those in to your methods to see how the code reacts to them. You no longer have to worry about your code depending on global state since there simply isn't any (at least none that we create).&lt;/P&gt;
&lt;P&gt;Have I given you enough context on what we're doing?&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=5816702" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/unit+test/default.aspx">unit test</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/aspnetmvc/default.aspx">aspnetmvc</category></item><item><title>ASP.NET MVC Design Philosophy</title><link>http://weblogs.asp.net/leftslipper/archive/2007/12/10/asp-net-mvc-design-philosophy.aspx</link><pubDate>Tue, 11 Dec 2007 02:00:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:5434791</guid><dc:creator>Eilon</dc:creator><slash:comments>39</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=5434791</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2007/12/10/asp-net-mvc-design-philosophy.aspx#comments</comments><description>&lt;P&gt;&lt;FONT size=3&gt;This week the first preview of the ASP.NET MVC framework was released to the web as part of the &lt;A href="http://asp.net/downloads/3.5-extensions/" mce_href="http://asp.net/downloads/3.5-extensions/"&gt;ASP.NET 3.5 Extensions CTP Preview&lt;/A&gt;. It's been a few months since we started coding and as the lead developer on the project I'd like to share my thoughts on the design of this framework. This isn't a post about why MVC is great. Instead, it's a post about what we did to make MVC happen in ASP.NET.&lt;/FONT&gt;&lt;/P&gt;
&lt;H2&gt;The MVC Snake&lt;/H2&gt;
&lt;P&gt;&lt;FONT size=+0&gt;One of the design strategies we used in the MVC framework is to have a clear sequence of stages in each request. The stages are reminiscent of the &lt;A href="http://msdn2.microsoft.com/en-us/library/ms178472.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms178472.aspx"&gt;ASP.NET Page and Controls lifecycle&lt;/A&gt;, but much, much simpler. Here's a rough diagram of the stages from the slides that &lt;A href="http://www.hanselman.com/blog/DevConnectionsTheASPNETMVCFramework.aspx" mce_href="http://www.hanselman.com/blog/DevConnectionsTheASPNETMVCFramework.aspx"&gt;Scott Hanselman&lt;/A&gt; and I showed at the DevConnections conference.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=3&gt;&lt;A href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCDesignPhilosophy_F491/MVC_Snake_2.png" mce_href="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCDesignPhilosophy_F491/MVC_Snake_2.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=184 alt=MVC_Snake src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCDesignPhilosophy_F491/MVC_Snake_thumb.png" width=244 border=0 mce_src="http://weblogs.asp.net/blogs/leftslipper/WindowsLiveWriter/ASP.NETMVCDesignPhilosophy_F491/MVC_Snake_thumb.png"&gt;&lt;/A&gt; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=3&gt;When a request comes in, it goes through the stages as shown in the diagram. There are a few more stages than are shown, but they were removed so the "MVC Snake" diagram wouldn't get too cluttered. An important aspect of this diagram is that each stage only depends on the previous stages. A given stage typically doesn't make any assumptions about what follows it.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=3&gt;For example, the IController interface doesn't assume anything about views or any particular view factory implementation. However, views can assume that an IController was involved in their creation. The implication of this is that you can stray from our path at almost any stage and still end up with success. Want to implement a controller in some new, unique way? Go ahead!&lt;/FONT&gt;&lt;/P&gt;
&lt;H2&gt;URL Routing - Not part of MVC&lt;FONT size=3&gt;&lt;/FONT&gt;&lt;/H2&gt;
&lt;P&gt;&lt;FONT size=3&gt;Part of the MVC framework is a new URL routing mechanism. This allows you to create "friendly" and "pretty" URLs such as "http://example.org/store/categories" that map to arbitrary controller actions. There's no reason that the URL should specify a physical resource. The visitors to your site surely don't care how you architected your web site or web application.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=3&gt;If you've downloaded the CTP you'll notice that the URL Routing types sit in the System.Web.Mvc namespace. However, the URL Routing types aren't even a part of the MVC framework. URL Routing works with arbitrary IHttpHandlers so it can serve up arbitrary requests - not just MVC requests. For the current CTP because we just couldn't find a better place so we left the types in that namespace.&lt;/FONT&gt;&lt;/P&gt;
&lt;H2&gt;New Language Features&lt;/H2&gt;
&lt;P&gt;&lt;FONT size=3&gt;We're technology addicts, and it shows. The latest version of the C# language includes several new features and we decided to take advantage of them in the MVC framework. We used &lt;/FONT&gt;&lt;FONT size=3&gt;&lt;A href="http://weblogs.asp.net/leftslipper/archive/2007/09/24/using-c-3-0-anonymous-types-as-dictionaries.aspx" mce_href="http://weblogs.asp.net/leftslipper/archive/2007/09/24/using-c-3-0-anonymous-types-as-dictionaries.aspx"&gt;anonymous types in place of dictionaries&lt;/A&gt;, extension methods for helper methods, and &lt;A href="http://blog.wekeroad.com/2007/12/05/aspnet-mvc-preview-using-the-mvc-ui-helpers/" mce_href="http://blog.wekeroad.com/2007/12/05/aspnet-mvc-preview-using-the-mvc-ui-helpers/"&gt;lambda expressions as strongly-typed URLs&lt;/A&gt;.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=3&gt;But - and there is almost always a "but" - we went a bit too far in the current CTP. We've heard from many of you already that using anonymous types as dictionaries is cool, but hard to understand. And it doesn't have Intellisense. For the next release we're still planning on keeping those features, but we want to add more familiar ways of doing the same things. For example, we're going to let you use dictionaries when we want dictionaries. It seems obvious now. :)&lt;/FONT&gt;&lt;/P&gt;
&lt;H2&gt;Extensible, Extensible, Extensible&lt;/H2&gt;
&lt;P&gt;&lt;FONT size=3&gt;To build a framework that was extensible, testable, and functional, we had many important design decisions to make.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=3&gt;Perhaps most importantly, we went with an interface-based design. We didn't use interfaces for &lt;EM&gt;everything&lt;/EM&gt;, but we did for most things. Typically we used i&lt;/FONT&gt;&lt;FONT size=3&gt;nterfaces for all &lt;EM&gt;behavioral &lt;/EM&gt;types, and classes for &lt;EM&gt;data objects&lt;/EM&gt;. The reason is that &lt;EM&gt;behavior &lt;/EM&gt;needs to be mocked, whereas &lt;EM&gt;data &lt;/EM&gt;is just data. Your data objects would probably look exactly the same as our implementations anyway, so we didn't want to bother with interfaces. There are always exceptions, and in the first CTP we may have made some decisions that don't agree with this, but we already have plans to address these for the next CTP.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=3&gt;Traditionally in ASP.NET, a lot of extensibility is enabled by inheriting from our classes and overriding virtual members. While it is a valid approach, it requires that you inherit from our components even if you just want to tweak one small behavior. In the MVC framework we still have many instances of that, but we also allow you to extend our functionality using composition. For example, to modify the behavior of a controller you can either derive from it or you can use a filter to externally change its behavior. The same exception I mentioned in the previous paragraph applies here.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=3&gt;Composition often yields better separation of concerns and allows you to more easily build cross-cutting concerns. For example, if you want to apply the same "behavior modification" to several different controller classes, you don't have to override the same virtual members in each one. You can just apply an external cross-cutting concern to the controllers you want. &lt;/FONT&gt;&lt;FONT size=3&gt;Thus, composition is more easily used with dependency injection frameworks.&lt;/FONT&gt;&lt;/P&gt;
&lt;H2&gt;What Does All This Lead To?&lt;/H2&gt;
&lt;P&gt;&lt;FONT size=3&gt;Well, what &lt;EM&gt;does&lt;/EM&gt; this all lead to? Several things, of course. For example, each of the components in the MVC framework is fairly small and self contained, with &lt;A href="http://en.wikipedia.org/wiki/Single_responsibility_principle" mce_href="http://en.wikipedia.org/wiki/Single_responsibility_principle"&gt;single responsibilities&lt;/A&gt;. This means that due to their small size you have building blocks that are easier to understand. It also means that you can replace or even alter the building blocks if they don't suit your needs.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=3&gt;Having great amounts of extensibility means you can write unit tests for your application more easily. I remember the days when I didn't write unit tests. Dark days, they were.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=3&gt;But who is going to use the MVC framework? Not everyone wants to write unit tests or alter so-called building blocks. Being able to drag &amp;amp; drop a GridView and a SqlDataSource onto a WebForm is a valid scenario and it will continue to work. We're trying to create a better fit for ASP.NET for certain types of individuals.&lt;/FONT&gt;&lt;/P&gt;
&lt;H2&gt;Anecdotes and Miscellany&lt;/H2&gt;
&lt;P&gt;&lt;FONT size=3&gt;And to end with some fun facts and stories, the following is all true.&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT size=3&gt;For the released CTP, the unit test code coverage numbers were about 93%, far more than any other major feature area. This does not include the code coverage by our QA guys, which I'm sure would bring the number up to at least 99%.&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;We had about 250 unit tests for MVC, and the ratio of unit test code to product code is about 1.9 to 1 (in terms of the size of the code files, not lines of code; I'm too lazy to do the latter!).&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;It &lt;EM&gt;feels&lt;/EM&gt; good to unit test! I can't go back to the old ways.&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;Some of the code is written using true TDD, but some is code-first, but it is then quickly followed up with unit tests (prior to checking in).&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;Several weeks ago we invited several customers for a top secret sneak preview of the CTP, including the MVC framework. &lt;A href="http://www.jeffreypalermo.com/" mce_href="http://www.jeffreypalermo.com/"&gt;Jeffrey Palermo&lt;/A&gt; was attending and trying to build some samples with the MVC framework. Sure enough, he encountered some bugs in the product. The bits were still hot off the press and some of the bits hadn't quite settled in the right place. Millions of ones and zeros - what are the odds they'd all line up correctly on the first try? Anyway, I sat with Jeffrey for about half an hour and we managed to use many of the extensibility points in the framework to work around the bugs he encountered. The whole time I kept thinking (and probably saying aloud) that I was &lt;EM&gt;so&lt;/EM&gt; glad I made those methods public or virtual or whatever! Without them Jeffrey would have been stuck.&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;The moral of the story: If you aren't sure, make it public. If &lt;EM&gt;we &lt;/EM&gt;have to use a method, chances are, someone &lt;EM&gt;else &lt;/EM&gt;does too.&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;H2&gt;MVC Resources&lt;/H2&gt;
&lt;P&gt;&lt;FONT size=3&gt;Downloads:&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT size=3&gt;&lt;A href="http://asp.net/downloads/3.5-extensions/" mce_href="http://asp.net/downloads/3.5-extensions/"&gt;Microsoft ASP.NET 3.5 Extensions Preview&lt;/A&gt; (the framework, which includes the MVC framework)&lt;/FONT&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;&lt;A href="http://asp.net/downloads/3.5-extensions/MVCToolkit.zip" mce_href="http://asp.net/downloads/3.5-extensions/MVCToolkit.zip"&gt;MVC Toolkit Extras&lt;/A&gt; (lots of helpers methods for MVC)&lt;/FONT&gt; &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;FONT size=3&gt;Documentation and discussion forums:&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT size=3&gt;&lt;A href="http://quickstarts.asp.net/3-5-extensions/" mce_href="http://quickstarts.asp.net/3-5-extensions/"&gt;QuickStart Documentation&lt;/A&gt;&lt;/FONT&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;&lt;A href="http://forums.asp.net/1146.aspx" mce_href="http://forums.asp.net/1146.aspx"&gt;ASP.NET MVC Forum&lt;/A&gt;&lt;/FONT&gt; &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;FONT size=3&gt;Blog posts and videos by team members:&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT size=3&gt;ScottGu: &lt;/FONT&gt;&lt;A href="http://weblogs.asp.net/scottgu/archive/2007/10/14/asp-net-mvc-framework.aspx" mce_href="http://weblogs.asp.net/scottgu/archive/2007/10/14/asp-net-mvc-framework.aspx"&gt;&lt;FONT size=3&gt;ASP.NET MVC Framework (Part 0): What is it?&lt;/FONT&gt;&lt;/A&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;ScottGu: &lt;/FONT&gt;&lt;A href="http://weblogs.asp.net/scottgu/archive/2007/11/13/asp-net-mvc-framework-part-1.aspx" mce_href="http://weblogs.asp.net/scottgu/archive/2007/11/13/asp-net-mvc-framework-part-1.aspx"&gt;&lt;FONT size=3&gt;ASP.NET MVC Framework (Part 1): Building an MVC Application&lt;/FONT&gt;&lt;/A&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;ScottGu: &lt;/FONT&gt;&lt;A href="http://weblogs.asp.net/scottgu/archive/2007/12/03/asp-net-mvc-framework-part-2-url-routing.aspx" mce_href="http://weblogs.asp.net/scottgu/archive/2007/12/03/asp-net-mvc-framework-part-2-url-routing.aspx"&gt;&lt;FONT size=3&gt;ASP.NET MVC Framework (Part 2): URL Routing&lt;/FONT&gt;&lt;/A&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;ScottGu: &lt;/FONT&gt;&lt;A href="http://weblogs.asp.net/scottgu/archive/2007/12/06/asp-net-mvc-framework-part-3-passing-viewdata-from-controllers-to-views.aspx" mce_href="http://weblogs.asp.net/scottgu/archive/2007/12/06/asp-net-mvc-framework-part-3-passing-viewdata-from-controllers-to-views.aspx"&gt;&lt;FONT size=3&gt;ASP.NET MVC Framework (Part 3): Passing ViewData from Controllers to Views&lt;/FONT&gt;&lt;/A&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;ScottGu: &lt;/FONT&gt;&lt;A href="http://weblogs.asp.net/scottgu/archive/2007/12/09/asp-net-mvc-framework-part-4-handling-form-edit-and-post-scenarios.aspx" mce_href="http://weblogs.asp.net/scottgu/archive/2007/12/09/asp-net-mvc-framework-part-4-handling-form-edit-and-post-scenarios.aspx"&gt;&lt;FONT size=3&gt;ASP.NET MVC Framework (Part 4): Handling Form Edit and Post Scenarios&lt;/FONT&gt;&lt;/A&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;Scott Hanselman: &lt;/FONT&gt;&lt;A href="http://www.hanselman.com/blog/ASPNET35ExtensionsPlusMVCHowToScreencast.aspx" mce_href="http://www.hanselman.com/blog/ASPNET35ExtensionsPlusMVCHowToScreencast.aspx"&gt;&lt;FONT size=3&gt;Scott Hanselman's ASP.NET MVC First Look Screencast&lt;/FONT&gt;&lt;/A&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;Phil Haack: &lt;/FONT&gt;&lt;A href="http://haacked.com/archive/2007/12/07/tdd-and-dependency-injection-with-asp.net-mvc.aspx" mce_href="http://haacked.com/archive/2007/12/07/tdd-and-dependency-injection-with-asp.net-mvc.aspx"&gt;&lt;FONT size=3&gt;TDD and Dependency Injection with the ASP.NET MVC Framework&lt;/FONT&gt;&lt;/A&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;Phil Haack: &lt;/FONT&gt;&lt;A href="http://haacked.com/archive/2007/12/09/writing-unit-tests-for-controller-actions.aspx" mce_href="http://haacked.com/archive/2007/12/09/writing-unit-tests-for-controller-actions.aspx"&gt;&lt;FONT size=3&gt;Writing Unit Tests for Controller Actions&lt;/FONT&gt;&lt;/A&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;Nikhil Kothari: &lt;/FONT&gt;&lt;A href="http://www.nikhilk.net/Ajax-MVC.aspx" mce_href="http://www.nikhilk.net/Ajax-MVC.aspx"&gt;&lt;FONT size=3&gt;Ajax with the ASP.NET MVC Framework&lt;/FONT&gt;&lt;/A&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;FONT size=3&gt;Brad Abrams: &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/brada/archive/2007/11/14/rss-feed-with-the-new-asp-net-mvc-framework.aspx" mce_href="http://blogs.msdn.com/brada/archive/2007/11/14/rss-feed-with-the-new-asp-net-mvc-framework.aspx"&gt;&lt;FONT size=3&gt;RSS Feed with the new ASP.NET MVC Framework&lt;/FONT&gt;&lt;/A&gt; &lt;/LI&gt;&lt;/UL&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=5434791" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/unit+test/default.aspx">unit test</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/MVC/default.aspx">MVC</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/aspnetmvc/default.aspx">aspnetmvc</category></item><item><title>Testing your ASP.NET control (part 1 of hopefully many): ViewState</title><link>http://weblogs.asp.net/leftslipper/archive/2007/05/31/testing-your-asp-net-control-part-1.aspx</link><pubDate>Thu, 31 May 2007 18:00:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:2699017</guid><dc:creator>Eilon</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/leftslipper/rsscomments.aspx?PostID=2699017</wfw:commentRss><comments>http://weblogs.asp.net/leftslipper/archive/2007/05/31/testing-your-asp-net-control-part-1.aspx#comments</comments><description>A typical ASP.NET server control will store at least some of its properties in ViewState. For example, the Label control saves the value of its Text property in ViewState so that on following postbacks the value does not need to be explicitly set again...(&lt;a href="http://weblogs.asp.net/leftslipper/archive/2007/05/31/testing-your-asp-net-control-part-1.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=2699017" width="1" height="1"&gt;</description><enclosure url="http://weblogs.asp.net/leftslipper/attachment/2699017.ashx" length="9249" type="application/x-zip-compressed" /><category domain="http://weblogs.asp.net/leftslipper/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/c_2300_/default.aspx">c#</category><category domain="http://weblogs.asp.net/leftslipper/archive/tags/unit+test/default.aspx">unit test</category></item></channel></rss>