如何使用 ASP.NET MVC 的最小起订量模拟 Request.ServerVariables?

发布于 2024-08-31 11:42:40 字数 1655 浏览 2 评论 0原文

当我开始了解模拟和现在存在的不同框架时,我刚刚学习为我的 ASP.NET MVC 进行单元测试。

检查后,我发现最小起订量似乎是最容易接受的。 截至目前,我一直在尝试模拟 Request.ServerVariables,如 读完这篇文章后,我了解到最好将它们抽象为属性。

因此:

/// <summary>
        /// Return the server port
        /// </summary>
        protected string ServerPort
        {
            get
            {
                return Request.ServerVariables.Get("SERVER_PORT");
            }
        }

但我很难学习如何正确地嘲笑这一点。 我有一个家庭控制器 ActionResult 函数,它获取用户服务器信息并继续创建一个表单来获取用户信息。

我尝试使用 hanselman 的 mvcmockhelpers 类 但我不知道如何使用它。

这就是我到目前为止所拥有的...

[Test]
        public void Create_Redirects_To_ProductAdded_On_Success() 
        {

            FakeViewEngine engine = new FakeViewEngine();

            HomeController controller = new HomeController();
            controller.ViewEngine = engine;

            MvcMockHelpers.SetFakeControllerContext(controller);

            controller.Create();

            var results = controller.Create();

            var typedResults = results as RedirectToRouteResult;

            Assert.AreEqual("", typedResults.RouteValues["action"], "Wrong action");
            Assert.AreEqual("", typedResults.RouteValues["controller"], "Wrong controller");
        }

问题:

  1. 到目前为止我仍然处于空状态 当我运行时出现异常错误 测试。那么我在这里缺少什么?
  2. 如果我使用 mvcmockhelpers 类,我怎么还能打电话 request.verifyall函数来确保 所有的模拟都正确设置了吗?

i'm just learning to put in unit testing for my asp.net mvc when i came to learn about the mock and the different frameworks there is out there now.

after checking SO, i found that MOQ seems to be the easiest to pick up.
as of now i'm stuck trying to mock the Request.ServerVariables, as after reading this post, i've learned that it's better to abstract them into property.

as such:

/// <summary>
        /// Return the server port
        /// </summary>
        protected string ServerPort
        {
            get
            {
                return Request.ServerVariables.Get("SERVER_PORT");
            }
        }

But i'm having a hard time learning how to properly mock this.
I have a home controller ActionResult function which grabs the user server information and proceed to create a form to grab the user's information.

i tried to use hanselman's mvcmockhelpers class but i'm not sure how to use it.

this is what i have so far...

[Test]
        public void Create_Redirects_To_ProductAdded_On_Success() 
        {

            FakeViewEngine engine = new FakeViewEngine();

            HomeController controller = new HomeController();
            controller.ViewEngine = engine;

            MvcMockHelpers.SetFakeControllerContext(controller);

            controller.Create();

            var results = controller.Create();

            var typedResults = results as RedirectToRouteResult;

            Assert.AreEqual("", typedResults.RouteValues["action"], "Wrong action");
            Assert.AreEqual("", typedResults.RouteValues["controller"], "Wrong controller");
        }

Questions:

  1. As of now i'm still getting null
    exception error when i'm running the
    test. So what am i missing here?
  2. And if i use the mvcmockhelpers
    class, how can i still call the
    request.verifyall function to ensure
    all the mocking are properly setup?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

花间憩 2024-09-07 11:42:40

所以基本上我已经输入了所有参考文献并使用这个函数我能够让它工作。我还没有使用 mvcmockhelpers 类,因为我仍在尝试学习所有这些。

对于任何有兴趣了解我如何解决这个问题的人,这是我使用的代码。

[Test]
public void Create_Returns_ViewResult_On_Success() 
{
  var server = new Mock<HttpServerUtilityBase>(MockBehavior.Loose);
  var response = new Mock<HttpResponseBase>(MockBehavior.Strict);

  var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
  request.Setup(x => x.ApplicationPath).Returns("/");
  request.Setup(x => x.Url).Returns(new Uri("http://localhost"));
  request.Setup(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection{
    { "SERVER_NAME", "localhost" },
    { "SCRIPT_NAME", "localhost" },
    { "SERVER_PORT", "80" },
    { "HTTPS", "www.melaos.com" },
    { "REMOTE_ADDR", "127.0.0.1" },
    { "REMOTE_HOST", "127.0.0.1" }
  });

  var context = new Mock<HttpContextBase>();
  context.SetupGet(x => x.Request).Returns(request.Object);
  context.SetupGet(x => x.Response).Returns(response.Object);
  context.SetupGet(x => x.Server).Returns(server.Object);

  var controller = new HomeController();
  //MvcMockHelpers.SetFakeControllerContext(controller);
  controller.ControllerContext = new ControllerContext(context. Object, new RouteData(), controller);

  var results = controller.Create();
  Assert.IsNotNull(results);
  Assert.IsInstanceOf(typeof(ViewResult), results);
}

so basically i've put in all the references and using this function i was able to get it working. i didn't use mvcmockhelpers class yet as i'm still trying to learn all of this.

and for anyone who's interested to see how i solved this, this is the code that i used.

[Test]
public void Create_Returns_ViewResult_On_Success() 
{
  var server = new Mock<HttpServerUtilityBase>(MockBehavior.Loose);
  var response = new Mock<HttpResponseBase>(MockBehavior.Strict);

  var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
  request.Setup(x => x.ApplicationPath).Returns("/");
  request.Setup(x => x.Url).Returns(new Uri("http://localhost"));
  request.Setup(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection{
    { "SERVER_NAME", "localhost" },
    { "SCRIPT_NAME", "localhost" },
    { "SERVER_PORT", "80" },
    { "HTTPS", "www.melaos.com" },
    { "REMOTE_ADDR", "127.0.0.1" },
    { "REMOTE_HOST", "127.0.0.1" }
  });

  var context = new Mock<HttpContextBase>();
  context.SetupGet(x => x.Request).Returns(request.Object);
  context.SetupGet(x => x.Response).Returns(response.Object);
  context.SetupGet(x => x.Server).Returns(server.Object);

  var controller = new HomeController();
  //MvcMockHelpers.SetFakeControllerContext(controller);
  controller.ControllerContext = new ControllerContext(context. Object, new RouteData(), controller);

  var results = controller.Create();
  Assert.IsNotNull(results);
  Assert.IsInstanceOf(typeof(ViewResult), results);
}
痴情 2024-09-07 11:42:40

由于我想模拟 HttpContext,而不是 HttpContextBase,因此我尝试找到一种将 HttpContextBase 模拟对象转换为 HttpContext 的方法,但发现这是不可能的。

HttpContext

这是老式的 asp.net 上下文。问题在于它
没有基类并且不是虚拟的,因此无法用于测试
(不能嘲笑它)。建议不要将其作为函数传递
参数,而不是传递 HttpContextBase 类型的变量。

HttpContextBase

这是 HttpContext 的(c# 3.5 新增功能)替代品。既然是
抽象的,现在是可嘲笑的。这个想法是你的功能
期望传递一个上下文应该期望收到其中之一。
具体由HttpContextWrapper实现

HttpContextWrapper

C# 3.5 中的新功能 - 这是具体实现
HttpContextBase。要在普通网页中创建其中之一,请使用 new
HttpContextWrapper(HttpContext.Current)。

这个想法是,为了使您的代码可进行单元测试,您需要声明所有
变量和函数参数的类型为 HttpContextBase,并且
使用 IOC 框架(例如 Castle Windsor)来注入它。正常情况下
代码中,castle就是注入相当于'new
HttpContextWrapper(HttpContext.Current)',而在测试代码中你是
获得 HttpContextBase 的模拟。

(来源:http://www.splinter.com .au/httpcontext-vs-httpcontextbase-vs-httpcontext/)

所以我改变了调用我的代码的方式。

从使用HttpContext

public static string GetIpAddress(HttpContext currentContext) {
 ...
}

到使用HttpContextBase

public static string GetIpAddress(HttpContextBase currentContext) {
 ...
}

当我使用该方法时,我用HttpContextWrapper包装HttpContext,如下所示:

var ip = GeneralUtil.GetIpAddress(new HttpContextWrapper(HttpContext.Current));

现在您可以按照 Dan Atkinson 的回复轻松模拟 HttpContextBase

Since I want to mock HttpContext, not HttpContextBase, I tried to find a way to convert HttpContextBase mock object to HttpContext and found out that it's impossible to do.

HttpContext

This is the vintage asp.net context. The problem with this is that it
has no base class and isn't virtual, and hence is unusable for testing
(cannot mock it). It's recommended to not pass it around as function
arguments, instead pass around variables of type HttpContextBase.

HttpContextBase

This is the (new to c# 3.5) replacement to HttpContext. Since it is
abstract, it is now mockable. The idea is that your functions that
expect to be passed a context should expect to receive one of these.
It is concretely implemented by HttpContextWrapper

HttpContextWrapper

Also new in C# 3.5 - this is the concrete implementation of
HttpContextBase. To create one of these in a normal webpage, use new
HttpContextWrapper(HttpContext.Current).

The idea is that to make your code unit-testable, you declare all your
variables and function parameters to be of type HttpContextBase, and
use an IOC framework eg Castle Windsor to get it injected. In normal
code, castle is to inject the equivalent of 'new
HttpContextWrapper(HttpContext.Current)', whereas in test code you're
to be given a mock of HttpContextBase.

(source: http://www.splinter.com.au/httpcontext-vs-httpcontextbase-vs-httpcontext/)

So I change the way to call my code.

From using HttpContext:

public static string GetIpAddress(HttpContext currentContext) {
 ...
}

To use HttpContextBase:

public static string GetIpAddress(HttpContextBase currentContext) {
 ...
}

And when I use the method, I wrap HttpContext with HttpContextWrapper like so:

var ip = GeneralUtil.GetIpAddress(new HttpContextWrapper(HttpContext.Current));

Now you can easily mock HttpContextBase by following Dan Atkinson's reply

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文