title: Moq-ing a 404 error
body: <p>I have the following 404 error ActionResult which is thrown when web pages are not found:</p>
  
  <pre><code>public ActionResult InvokeHttp404(HttpContextBase httpContext) {
        IController errorController = new ErrorController();
        var errorRoute = new RouteData();
        errorRoute.Values.Add("controller", "Error");
        errorRoute.Values.Add("action", "Http404");
        errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
        errorController.Execute(new RequestContext(httpContext, errorRoute));
        return new EmptyResult();
      }
  </code></pre>
  
  <p>And I am attempting to unit test it with the following test:</p>
  
  <pre><code>[TestMethod]
          public void Details_Get_404Handler()
          {
              // Arrange
              var controller = GetController(new Repository(), FakeHttpContext());
  
              // Act
              var result = controller.Details(3442399) as ViewResult; // invalid Id (not found)
  
              //Assert
              Assert.AreEqual("NotFound", result.ViewName);
          }
  </code></pre>
  
  <p>I have been stuck on this test for a long time now, it would throw a null exception on the line of code that requests the <code>Url.OriginalString</code>. After reading around I found this previous post <a href="https://stackoverflow.com/questions/1228179/mocking-httpcontextbase-with-moq">Mocking HttpContextBase with Moq</a> and found the second answer very helpful, as follows: (I added a line that took care of the Url string)</p>
  
  <pre><code>public static HttpContextBase FakeHttpContext()
          {
              var context = new Mock&lt;HttpContextBase&gt;();
              var request = new Mock&lt;HttpRequestBase&gt;();
              var response = new Mock&lt;HttpResponseBase&gt;();
              var session = new Mock&lt;HttpSessionStateBase&gt;();
              var server = new Mock&lt;HttpServerUtilityBase&gt;();
              var user = new Mock&lt;IPrincipal&gt;();
              var identity = new Mock&lt;IIdentity&gt;();
  
              request.SetupGet(x =&gt; x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute));
              request.Setup(req =&gt; req.ApplicationPath).Returns("~/");
              request.Setup(req =&gt; req.AppRelativeCurrentExecutionFilePath).Returns("~/");
              request.Setup(req =&gt; req.PathInfo).Returns(string.Empty);
              response.Setup(res =&gt; res.ApplyAppPathModifier(It.IsAny&lt;string&gt;()))
                  .Returns((string virtualPath) =&gt; virtualPath);
              user.Setup(usr =&gt; usr.Identity).Returns(identity.Object);
              identity.SetupGet(ident =&gt; ident.IsAuthenticated).Returns(true);
  
              context.Setup(ctx =&gt; ctx.Request).Returns(request.Object);
              context.Setup(ctx =&gt; ctx.Response).Returns(response.Object);
              context.Setup(ctx =&gt; ctx.Session).Returns(session.Object);
              context.Setup(ctx =&gt; ctx.Server).Returns(server.Object);
              context.Setup(ctx =&gt; ctx.User).Returns(user.Object);
  
              return context.Object;
          }
  </code></pre>
  
  <p>So I have finally beaten the line of code requesting the Url.OriginalString thanks to that post and answer. But I am now stuck on line of code straight after it:
  <code>errorController.Execute(new RequestContext(httpContext, errorRoute));</code>. The test now fails with a null reference error on that line. I am slightly confused as to what is null here as I have already faked the httpContext. Could anyone help me with this?</p>
  
  <p>Edit:</p>
  
  <p>Altered ValueProviderFactoriesExtensions:</p>
  
  <pre><code>public static class ValueProviderFactoresExtensions
  {
      public static ValueProviderFactoryCollection ReplaceNameValueCollectionWith&lt;TOriginal&gt;(this ValueProviderFactoryCollection factories, Func&lt;ControllerContext, NameValueCollection&gt; sourceAccessor)
      {
          var original = factories.FirstOrDefault(x =&gt; typeof(TOriginal) == x.GetType());
          if (original != null)
          {
              var index = factories.IndexOf(original);
              factories[index] = new NameValueCollectionProviderFactory(sourceAccessor);
          }
          return factories;
      }
  
      public static ValueProviderFactoryCollection ReplaceHttpFileCollectionWith&lt;TOriginal&gt;(this ValueProviderFactoryCollection factories, Func&lt;ControllerContext, HttpFileCollectionBase&gt; sourceAccessor)
      {
          var original = factories.FirstOrDefault(x =&gt; typeof(TOriginal) == x.GetType());
          if (original != null)
          {
              var index = factories.IndexOf(original);
              factories[index] = new HttpFileCollectionProviderFactory(sourceAccessor);
          }
          return factories;
      }
  
      class NameValueCollectionProviderFactory : ValueProviderFactory
      {
          private readonly Func&lt;ControllerContext, NameValueCollection&gt; sourceAccessor;
  
  
          public NameValueCollectionProviderFactory(Func&lt;ControllerContext, NameValueCollection&gt; sourceAccessor)
          {
              this.sourceAccessor = sourceAccessor;
          }
  
  
          public override IValueProvider GetValueProvider(ControllerContext controllerContext)
          {
              return new NameValueCollectionValueProvider(sourceAccessor(controllerContext), CultureInfo.CurrentCulture);
          }
  
      }
      class HttpFileCollectionProviderFactory : ValueProviderFactory
      {
          private readonly Func&lt;ControllerContext, HttpFileCollectionBase&gt; sourceAccessor;
  
  
          public HttpFileCollectionProviderFactory(Func&lt;ControllerContext, HttpFileCollectionBase&gt; sourceAccessor)
          {
              this.sourceAccessor = sourceAccessor;
          }
  
  
          public override IValueProvider GetValueProvider(ControllerContext controllerContext)
          {
              return new HttpFileCollectionValueProvider(controllerContext);
          }
  
      }
  }
  </code></pre>
  
  <p>Code altered in response to Marnix's answer:</p>
  
  <pre><code>public static HttpContextBase FakeHttpContext()
          {
              var context = new Mock&lt;HttpContextBase&gt;();
              var request = new Mock&lt;HttpRequestBase&gt;();
              var response = new Mock&lt;HttpResponseBase&gt;();
              var session = new Mock&lt;HttpSessionStateBase&gt;();
              var server = new Mock&lt;HttpServerUtilityBase&gt;();
              var user = new Mock&lt;IPrincipal&gt;();
              var identity = new Mock&lt;IIdentity&gt;();
              var files = new Mock&lt;HttpFileCollectionBase&gt;();
  
  
  
              request.SetupGet(x =&gt; x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute));
              request.Setup(req =&gt; req.ApplicationPath).Returns("~/");
              request.Setup(req =&gt; req.AppRelativeCurrentExecutionFilePath).Returns("~/");
              request.Setup(req =&gt; req.PathInfo).Returns(string.Empty);
              request.Setup(req =&gt; req.ContentType).Returns("text/html");
              request.Setup(req =&gt; req.QueryString).Returns(new NameValueCollection());
              request.Setup(req =&gt; req.Form).Returns(new NameValueCollection());
              request.Setup(req =&gt; req.Files).Returns(files.Object);
              response.Setup(res =&gt; res.ApplyAppPathModifier(It.IsAny&lt;string&gt;()))
                  .Returns((string virtualPath) =&gt; virtualPath);
              user.Setup(usr =&gt; usr.Identity).Returns(identity.Object);
              identity.SetupGet(ident =&gt; ident.IsAuthenticated).Returns(true);
              context.Setup(ctx =&gt; ctx.Request).Returns(request.Object);
              context.Setup(ctx =&gt; ctx.Response).Returns(response.Object);
              context.Setup(ctx =&gt; ctx.Session).Returns(session.Object);
              context.Setup(ctx =&gt; ctx.Server).Returns(server.Object);
              context.Setup(ctx =&gt; ctx.User).Returns(user.Object);
  
              ValueProviderFactories.Factories
                  .ReplaceNameValueCollectionWith&lt;FormValueProviderFactory&gt;(ctx =&gt; ctx.HttpContext.Request.Form)
                  .ReplaceNameValueCollectionWith&lt;QueryStringValueProviderFactory&gt;(ctx =&gt; ctx.HttpContext.Request.QueryString)
                  .ReplaceHttpFileCollectionWith&lt;HttpFileCollectionValueProviderFactory&gt;(ctx =&gt; ctx.HttpContext.Request.Files);
  
              return context.Object;
          }
  </code></pre>
  
  <p>Still can't get it to work, still throws a null reference on the same line of code. Don't know if stack trace is struggling to find view? stack trace:</p>
  
  <pre><code>System.Web.Mvc.ViewResult.FindView(ControllerContext context)
  </code></pre>