asp.net-mvc ASP/NET MVC:带会话的测试控制器?嘲讽?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/176347/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-07 22:46:33  来源:igfitidea点击:

ASP/NET MVC: Test Controllers w/Sessions? Mocking?

asp.net-mvcunit-testingmockingsession

提问by Codewerks

I read some of the answers on here re: testing views and controllers, and mocking, but I still can't figure out how to test an ASP.NET MVC controller that reads and sets Session values (or any other context based variables.) How do I provide a (Session) context for my test methods? Is mocking the answer? Anybody have examples? Basically, I'd like to fake a session before I call the controller method and have the controller use that session. Any ideas?

我在这里阅读了一些答案:测试视图和控制器以及模拟,但我仍然无法弄清楚如何测试读取和设置会话值(或任何其他基于上下文的变量)的 ASP.NET MVC 控制器。如何为我的测试方法提供(会话)上下文?是在嘲讽答案吗?有人有例子吗?基本上,我想在调用控制器方法并让控制器使用该会话之前伪造一个会话。有任何想法吗?

回答by David P

Check out Stephen Walther's post on Faking the Controller Context:

查看 Stephen Walther 关于伪造控制器上下文的帖子:

ASP.NET MVC Tip #12 – Faking the Controller Context

ASP.NET MVC 技巧 #12 – 伪造控制器上下文

[TestMethod]
public void TestSessionState()
{
    // Create controller
    var controller = new HomeController();


    // Create fake Controller Context
    var sessionItems = new SessionStateItemCollection();
    sessionItems["item1"] = "wow!";
    controller.ControllerContext = new FakeControllerContext(controller, sessionItems);
    var result = controller.TestSession() as ViewResult;


    // Assert
    Assert.AreEqual("wow!", result.ViewData["item1"]);

    // Assert
    Assert.AreEqual("cool!", controller.HttpContext.Session["item2"]);
}

回答by chadmyers

The ASP.NET MVC framework is not very mock-friendly (or rather, requires too much setup to mock properly, and causes too much friction when testing, IMHO) due to it's use of abstract base classes instead of interfaces. We've had good luck writing abstractions for per-request and session-based storage. We keep those abstractions very light and then our controllers depend upon those abstractions for per-request or per-session storage.

由于 ASP.NET MVC 框架使用抽象基类而不是接口,因此 ASP.NET MVC 框架对模拟不是很友好(或者更确切地说,需要太多设置才能正确模拟,并且在测试时会导致太多摩擦,恕我直言)。我们很幸运地为每个请求和基于会话的存储编写了抽象。我们保持这些抽象非常轻,然后我们的控制器依赖这些抽象来存储每个请求或每个会话。

For example, here's how we manage the forms auth stuff. We have an ISecurityContext:

例如,这里是我们如何管理表单身份验证的东西。我们有一个 ISecurityContext:

public interface ISecurityContext
{
    bool IsAuthenticated { get; }
    IIdentity CurrentIdentity { get; }
    IPrincipal CurrentUser { get; set; }
}

With a concrete implementation like:

有一个具体的实现,如:

public class SecurityContext : ISecurityContext
{
    private readonly HttpContext _context;

    public SecurityContext()
    {
        _context = HttpContext.Current;
    }

    public bool IsAuthenticated
    {
        get { return _context.Request.IsAuthenticated; }
    }

    public IIdentity CurrentIdentity
    {
        get { return _context.User.Identity; }
    }

    public IPrincipal CurrentUser
    {
        get { return _context.User; }
        set { _context.User = value; }
    }
}

回答by Dane O'Connor

With MVC RC 1 the ControllerContext wraps the HttpContext and exposes it as a property. This makes mocking much easier. To mock a session variable with Moq do the following:

在 MVC RC 1 中,ControllerContext 包装了 HttpContext 并将其作为属性公开。这使得模拟更容易。要使用 Moq 模拟会话变量,请执行以下操作:

var controller = new HomeController();
var context = MockRepository.GenerateStub<ControllerContext>();
context.Expect(x => x.HttpContext.Session["MyKey"]).Return("MyValue");
controller.ControllerContext = context;

See Scott Gu's postfor more details.

有关更多详细信息,请参阅Scott Gu 的帖子

回答by Korbin

I found mocking to be fairly easy. Here is an example of mocking the httpContextbase (that contains the request, session and response objects) using moq.

我发现嘲笑相当容易。这是一个使用 moq 模拟 httpContextbase(包含请求、会话和响应对象)的示例。

[TestMethod]
        public void HowTo_CheckSession_With_TennisApp() {
            var request = new Mock<HttpRequestBase>();
            request.Expect(r => r.HttpMethod).Returns("GET");     

            var httpContext = new Mock<HttpContextBase>();
            var session = new Mock<HttpSessionStateBase>();

            httpContext.Expect(c => c.Request).Returns(request.Object);
            httpContext.Expect(c => c.Session).Returns(session.Object);

            session.Expect(c => c.Add("test", "something here"));            

            var playerController = new NewPlayerSignupController();
            memberController.ControllerContext = new ControllerContext(new RequestContext(httpContext.Object, new RouteData()), playerController);          

            session.VerifyAll(); // function is trying to add the desired item to the session in the constructor
            //TODO: Add Assertions   
        }

Hope that helps.

希望有帮助。

回答by Mathias Lykkegaard Lorenzen

I used the following solution - making a controller that all my other controllers inherit from.

我使用了以下解决方案 - 制作一个我所有其他控制器都继承自的控制器。

public class TestableController : Controller
{

    public new HttpSessionStateBase Session
    {
        get
        {
            if (session == null)
            {
                session = base.Session ?? new CustomSession();
            }
            return session;
        }
    }
    private HttpSessionStateBase session;

    public class CustomSession : HttpSessionStateBase
    {

        private readonly Dictionary<string, object> dictionary; 

        public CustomSession()
        {
            dictionary = new Dictionary<string, object>();
        }

        public override object this[string name]
        {
            get
            {
                if (dictionary.ContainsKey(name))
                {
                    return dictionary[name];
                } else
                {
                    return null;
                }
            }
            set
            {
                if (!dictionary.ContainsKey(name))
                {
                    dictionary.Add(name, value);
                }
                else
                {
                    dictionary[name] = value;
                }
            }
        }

        //TODO: implement other methods here as needed to forefil the needs of the Session object. the above implementation was fine for my needs.

    }

}

Then use the code as follows:

然后使用代码如下:

public class MyController : TestableController { }

回答by Nick DeVore

Scott Hanselman has a post about how to create a file uploadquickapp with MVC and discusses moking and specifically addresses "How to mock things that aren't mock friendly."

Scott Hanselman 发表了一篇关于如何使用 MVC创建文件上传快速应用程序的帖子,并讨论了 moking 并专门解决了“如何模拟不友好的模拟事物”。

回答by Nick DeVore

Because HttpContext is static, I use Typemock Isolator to mock it, Typemock also has an Add-in custom built for ASP.NET unit testingcalled Ivonna.

因为 HttpContext 是静态的,所以我使用 Typemock Isolator 来模拟它,Typemock 还有一个为ASP.NET 单元测试构建的插件自定义,称为Ivonna