2011-03-28 19 views
11

我已经看到很多关于HttpSessionState和asp.net MVC的讨论。 我想写一个asp.net应用程序的测试,并想知道是否有可能嘲笑HttpSessionState,如果是这样,如何?在ASP.net中嘲笑HttpSessionState进行nunit测试

我目前使用犀牛制品和NUnit

+0

如果你在谈论的WebForms,这是http://stackoverflow.com/questions/1981426/how-do-i-mock-fake-the-s的副本ession-object-in-asp-net-web-forms – PHeiberg 2011-03-28 19:27:01

回答

1

请看System.Web.Abstractions中的HttpSessionStateBaseHttpSessionStateWrapper类。 HttpSessionStateBaseHttpSessionState继承的抽象类,HttpSessionStateWrapper用于包装抽象类中的密封类,然后您可以在测试中模拟它。

许多System.Web类都是密封的(例如,HttpSessionState),所以当您有与它们交互的方法和类时测试代码是一件非常痛苦的事情。我喜欢一个模式来使用来解决这个问题如下所示:

public void DoSomething(HttpSessionState state) 
{ 
    // take this HttpSeassionState and create an abstract HttpSessionStateBase 
    // instance 
    DoSomething(new HttpSessionStateWrapper(state)); 
} 

internal void DoSomething(HttpSessionStateBase state) 
{ 
    // my actual logic for working with the session state 
} 

公共方法难以测试,因为HttpSessionState是密封的,你不能嘲笑它。但是,内部方法在HttpSessionStateBase实例上运行,您可以使用模拟。请注意,我已将其标记为内部,因为我不希望外部世界能够访问该方法。不过,我想我的测试才能够访问,所以我会改变我的AssemblyInfo.cs,包括这样的事情:

[assembly: InternalsVisibleTo("Vendor.Utilities.Tests")] 

最后,我为这个测试会是这个样子:

[Test] 
public void Test_DoSomething() 
{ 
    HttpSessionStateBase state = MockRepository.PartialMock<HttpSessionStateBase>(); 
    state.Expect(s => ...); 

    MyClass.DoSomething(state); 

    state.VerifyAllExpectations(); 
} 

希望有所帮助。祝你好运!

11

吉尔伯特,

也许我为你太晚了。我正在使用MSpec,但我认为这些概念是相似的。我需要在被测试的控制器中模拟HttpContext的几个组件。

我开始用下面的这些类来模拟HttpContextBase中必要的(用于我的目的)组件。我只覆盖了课程中的必要部分。您的需求会因您在控制器中需要的模拟而异。一旦理解了模式,就可以根据需要添加模拟。

public class MockHttpContext : HttpContextBase 
{ 

    private readonly HttpRequestBase _request = new MockHttpRequest(); 
    private readonly HttpServerUtilityBase _server = new MockHttpServerUtilityBase(); 
    private HttpSessionStateBase _session = new MockHttpSession(); 

    public override HttpRequestBase Request 
    { 
     get { return _request; } 
    } 
    public override HttpServerUtilityBase Server 
    { 
     get { return _server; } 
    } 
    public override HttpSessionStateBase Session 
    { 
     get { return _session; } 
    } 
} 

public class MockHttpRequest : HttpRequestBase 
{ 
    private Uri _url = new Uri("http://www.mockrequest.moc/Controller/Action"); 

    public override Uri Url 
    { 
     get { return _url; } 
    } 
} 

public class MockHttpServerUtilityBase : HttpServerUtilityBase 
{ 
    public override string UrlEncode(string s) 
    { 
     //return base.UrlEncode(s);  
     return s;  // Not doing anything (this is just a Mock) 
    } 
} 


public class MockHttpSession : HttpSessionStateBase 
{ 
    // Started with sample http://stackoverflow.com/questions/524457/how-do-you-mock-the-session-object-collection-using-moq 
    // from http://stackoverflow.com/users/81730/ronnblack 

    System.Collections.Generic.Dictionary<string, object> _sessionStorage = new System.Collections.Generic.Dictionary<string,object>(); 
    public override object this[string name] 
    { 
     get { return _sessionStorage[name]; } 
     set { _sessionStorage[name] = value; } 
    } 

    public override void Add(string name, object value) 
    { 
     _sessionStorage[name] = value; 
    } 
} 

这是我如何设置控制器上下文以使用模拟(MSpec)。这是对位指示的实际测试设置(测试从这个类派生)

public abstract class BlahBlahControllerContext 
{ 
    protected static BlahBlahController controller; 

    Establish context =() => 
    { 
     controller = new BlahBlahController(); 
     controller.ControllerContext = new ControllerContext() 
     { 
      Controller = controller, 
      RequestContext = new RequestContext(new MockHttpContext(), new RouteData()), 
     }; 
    }; 
} 

为了进一步说明这里是(在MSpec世界规范)测试使用模拟会话:

[Subject("ACCOUNT: Retrieve Password")] 
public class retrieve_password_displays_retrieve_password2_page_on_success : BlahBlahControllerContext 
{ 
    static ActionResult result; 
    static RetrievePasswordModel model; 

    Establish context =() => 
    { 
     model = new RetrievePasswordModel() 
     { 
      UserName = "Mike" 
     }; 
    }; 

    Because of =() => 
    { 
     result = controller.RetrievePassword(model); 
    }; 

    It should_return_a_RedirectToRouteResult =() => 
    { 
     result.is_a_redirect_to_route_and().action_name().ShouldEqual("RetrievePassword2"); 
    }; 

    It session_should_contain_UN_value =() => 
    { 
     controller.HttpContext.Session["UN"].ShouldEqual("Mike"); 
    }; 

    It session_should_contain_PQ_value =() => 
    { 
     controller.HttpContext.Session["PQ"].ShouldEqual("Question"); 
    }; 
} 

我意识到这并不使用Rhino Mocks。我希望它能说明这些原则,读者可以将其应用于其特定的工具和方法。

7

如果您需要为遗留代码测试准确地实例化HttpSessionState,则可以利用FormatterServices机制获取未初始化的对象。得到它的工作是需要在内部构造

例,虽然设置私有_container领域,如:

var state = (HttpSessionState) System.Runtime.Serialization 
    .FormatterServices.GetUninitializedObject(typeof(HttpSessionState)); 

var containerFld = typeof(HttpSessionState).GetField(
    "_container", BindingFlags.Instance | BindingFlags.NonPublic); 

var itemCollection = new SessionStateItemCollection(); 
itemCollection["element"] = 1; 

containerFld.SetValue(
    state, 
    new HttpSessionStateContainer(
     "1", 
     itemCollection, 
     new HttpStaticObjectsCollection(), 
     900, 
     true, 
     HttpCookieMode.UseCookies, 
     SessionStateMode.InProc, 
     false 
    ) 
); 
+0

这是我的一天。正是我个人需要它和工作。谢谢。 – Bokonon 2015-09-04 15:23:09

+0

太棒了。你拯救了我的一天(y) – Erwin 2016-05-11 10:44:44

0

这是我做了基于他人的贡献......

公共类MockWebContext {

public Mock<RequestContext> RoutingRequestContext { get; private set; } 
    public Mock<HttpContextBase> Http { get; private set; } 
    public Mock<HttpServerUtilityBase> Server { get; private set; } 
    public Mock<HttpResponseBase> Response { get; private set; } 
    public Mock<HttpRequestBase> Request { get; private set; } 
    public Mock<HttpSessionStateBase> Session { get; private set; } 
    public Mock<ActionExecutingContext> ActionExecuting { get; private set; } 
    public HttpCookieCollection Cookies { get; private set; } 

    private IDictionary items; 

    public MockWebContext() 
    { 
     RoutingRequestContext = new Mock<RequestContext>(MockBehavior.Loose); 
     ActionExecuting = new Mock<ActionExecutingContext>(MockBehavior.Loose); 
     Http = new Mock<HttpContextBase>(MockBehavior.Loose); 
     Server = new Mock<HttpServerUtilityBase>(MockBehavior.Loose); 
     Response = new Mock<HttpResponseBase>(MockBehavior.Loose); 
     Request = new Mock<HttpRequestBase>(MockBehavior.Loose); 
     Session = new Mock<HttpSessionStateBase>(MockBehavior.Loose); 
     Cookies = new HttpCookieCollection(); 

     items = new Dictionary<string, object>(); 

     RoutingRequestContext.SetupGet(c => c.HttpContext).Returns(Http.Object); 
     ActionExecuting.SetupGet(c => c.HttpContext).Returns(Http.Object); 
     Http.SetupGet(c => c.Request).Returns(Request.Object); 
     Http.SetupGet(c => c.Response).Returns(Response.Object); 
     Http.SetupGet(c => c.Server).Returns(Server.Object); 
     Http.SetupGet(c => c.Session).Returns(Session.Object); 
     Http.SetupGet(c => c.Items).Returns(items); 
     Request.Setup(c => c.Cookies).Returns(Cookies); 
     Request.Setup(c => c.RequestContext).Returns(RoutingRequestContext.Object); 
     Response.Setup(c => c.Cookies).Returns(Cookies); 
     Session.Setup(c => 
      c.Add(It.IsAny<string>(), It.IsAny<object>())     
      ).Callback((string key, object value)=> items.Add(key, value)); 

     Session.Setup(c => 
      c.Remove(It.IsAny<string>()) 
     ).Callback((string key) => items.Remove(key)); 


     Session.Setup(c => 
      c.Clear() 
     ).Callback(() => items.Clear()); 

     Session.Setup(c => 
     c[It.IsAny<string>()] 
     ).Returns((string key)=> items[key]); 


    } 

}