Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/asp.net-mvc-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net mvc 3 Moq正在显示404错误_Asp.net Mvc 3_Unit Testing_Nunit_Moq_Http Status Code 404 - Fatal编程技术网

Asp.net mvc 3 Moq正在显示404错误

Asp.net mvc 3 Moq正在显示404错误,asp.net-mvc-3,unit-testing,nunit,moq,http-status-code-404,Asp.net Mvc 3,Unit Testing,Nunit,Moq,Http Status Code 404,我有以下404错误ActionResult,当找不到网页时会抛出: public ActionResult InvokeHttp404(HttpContextBase httpContext) { IController errorController = new ErrorController(); var errorRoute = new RouteData(); errorRoute.Values.Add("controller", "Error");

我有以下404错误ActionResult,当找不到网页时会抛出:

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();
    }
我试图通过以下测试对其进行单元测试:

[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);
        }
我已经在这个测试上呆了很长时间了,它会在请求
Url.OriginalString
的代码行上抛出一个null异常。在阅读了之前的文章后,我发现第二个答案非常有帮助,如下所示:(我添加了一行内容来处理Url字符串)

根据Marnix的回答修改代码:

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 user = new Mock<IPrincipal>();
            var identity = new Mock<IIdentity>();
            var files = new Mock<HttpFileCollectionBase>();



            request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute));
            request.Setup(req => req.ApplicationPath).Returns("~/");
            request.Setup(req => req.AppRelativeCurrentExecutionFilePath).Returns("~/");
            request.Setup(req => req.PathInfo).Returns(string.Empty);
            request.Setup(req => req.ContentType).Returns("text/html");
            request.Setup(req => req.QueryString).Returns(new NameValueCollection());
            request.Setup(req => req.Form).Returns(new NameValueCollection());
            request.Setup(req => req.Files).Returns(files.Object);
            response.Setup(res => res.ApplyAppPathModifier(It.IsAny<string>()))
                .Returns((string virtualPath) => virtualPath);
            user.Setup(usr => usr.Identity).Returns(identity.Object);
            identity.SetupGet(ident => ident.IsAuthenticated).Returns(true);
            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.User).Returns(user.Object);

            ValueProviderFactories.Factories
                .ReplaceNameValueCollectionWith<FormValueProviderFactory>(ctx => ctx.HttpContext.Request.Form)
                .ReplaceNameValueCollectionWith<QueryStringValueProviderFactory>(ctx => ctx.HttpContext.Request.QueryString)
                .ReplaceHttpFileCollectionWith<HttpFileCollectionValueProviderFactory>(ctx => ctx.HttpContext.Request.Files);

            return context.Object;
        }

模拟控制器的上下文有点棘手。在MVC3中,还有一个额外的步骤来防止值提供程序接触HttpContext.Current

解释你需要做什么

更新:您可能不会直接使用ValueProviderFactorys,但控制器上的ActionInvoker会直接使用。在深层的某个地方,值提供程序的默认实现访问HttpContext.Current,HttpContext.Current不是在web请求之外设置的,在单元测试期间会导致NullReferenceException。您可以通过替换默认值提供程序(如链接答案中所述)来防止这种情况

将上面链接中的
valueProviderFactoryExtensions
类复制到您的测试项目中,并将以下代码添加到您的
FakeHttpContext
方法中:

var form = new NameValueCollection();
var queryString = new NameValueCollection();

request.Setup( x => x.Form ).Returns( form );
request.Setup( x => x.QueryString ).Returns( queryString );

ValueProviderFactories.Factories
.ReplaceWith<FormValueProviderFactory>(ctx => form)
.ReplaceWith<QueryStringValueProviderFactory>(ctx => queryString);
var form=new NameValueCollection();
var queryString=new NameValueCollection();
request.Setup(x=>x.Form).Returns(Form);
request.Setup(x=>x.QueryString).Returns(QueryString);
价值提供者工厂。工厂
.ReplaceWith(ctx=>form)
.replace为(ctx=>queryString);

我有一个像问题中那个家伙一样的错误控制器,但我要问的是如何使用MOQ对404错误控制器进行单元测试。以前没有使用ValueProviderFactorys,考虑到您所指的问题中有ValueProviderFactoryExtensions类,我可以从测试方法中显示如何调用它们吗?如果有人有解决方案,我仍然希望在Moq中看到解决方案…我更新了我的答案,解释了如何以及为什么需要调整ValueProviderFactorys。测试结果详细信息中的堆栈跟踪现在已经超过了namevaluecollections,但现在似乎无法找到viewname?我已经发布了我在我的问题中使用的更新代码-它和你说的不完全一样,但有相同的区别,对吗?看起来差不多。我的最佳猜测是,您的错误控制器正在尝试返回视图结果。调用
Execute
时,将执行整个管道,包括视图。由于您正在进行单元测试,ViewEngine很可能无法找到视图。你有两个选择;终止视图引擎或重新考虑实现控制器的方式。例如,您可以抛出错误代码为404的HttpException,并使用自定义HandleErrorAttribute实现处理该异常。这将使您的控制器更易于测试。
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 user = new Mock<IPrincipal>();
            var identity = new Mock<IIdentity>();
            var files = new Mock<HttpFileCollectionBase>();



            request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute));
            request.Setup(req => req.ApplicationPath).Returns("~/");
            request.Setup(req => req.AppRelativeCurrentExecutionFilePath).Returns("~/");
            request.Setup(req => req.PathInfo).Returns(string.Empty);
            request.Setup(req => req.ContentType).Returns("text/html");
            request.Setup(req => req.QueryString).Returns(new NameValueCollection());
            request.Setup(req => req.Form).Returns(new NameValueCollection());
            request.Setup(req => req.Files).Returns(files.Object);
            response.Setup(res => res.ApplyAppPathModifier(It.IsAny<string>()))
                .Returns((string virtualPath) => virtualPath);
            user.Setup(usr => usr.Identity).Returns(identity.Object);
            identity.SetupGet(ident => ident.IsAuthenticated).Returns(true);
            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.User).Returns(user.Object);

            ValueProviderFactories.Factories
                .ReplaceNameValueCollectionWith<FormValueProviderFactory>(ctx => ctx.HttpContext.Request.Form)
                .ReplaceNameValueCollectionWith<QueryStringValueProviderFactory>(ctx => ctx.HttpContext.Request.QueryString)
                .ReplaceHttpFileCollectionWith<HttpFileCollectionValueProviderFactory>(ctx => ctx.HttpContext.Request.Files);

            return context.Object;
        }
System.Web.Mvc.ViewResult.FindView(ControllerContext context)
var form = new NameValueCollection();
var queryString = new NameValueCollection();

request.Setup( x => x.Form ).Returns( form );
request.Setup( x => x.QueryString ).Returns( queryString );

ValueProviderFactories.Factories
.ReplaceWith<FormValueProviderFactory>(ctx => form)
.ReplaceWith<QueryStringValueProviderFactory>(ctx => queryString);