2011-03-28 19 views
11

के लिए ASP.net में HttpSessionState का मज़ाक उड़ाते हुए मैंने HttpSessionState और asp.net MVC के आस-पास कई चर्चाएं देखी हैं। मैं एएसपीनेट एप्लिकेशन के लिए परीक्षण लिखने की कोशिश कर रहा हूं और सोच रहा हूं कि HttpSessionState को नकल करना संभव है और यदि ऐसा है, तो कैसे?Nunit परीक्षण

मैं वर्तमान में राइनो मजाक उड़ाता है और Nunit

+0

आप webforms बारे में बात कर रहे हैं, यह http://stackoverflow.com/questions/1981426/how-do-i-mock-fake-the-s का डुप्लिकेट है ession-object-in-asp-net-web-form – PHeiberg

उत्तर

1

और HttpSessionStateWrapper कक्षाओं को System.Web.Abstractions में देखें। HttpSessionStateBase अमूर्त वर्ग है जिसमें से HttpSessionState विरासत है, और 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

गिल्बर्ट,

शायद मैं आपके लिए बहुत देर हो चुकी हूं। मैं एमएसपीसी का उपयोग कर रहा हूं, लेकिन मुझे लगता है कि अवधारणाएं समान हैं। मुझे परीक्षण के तहत नियंत्रकों में 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; 
    } 
} 

मैक्स (एमएसपीईसी) का उपयोग करने के लिए मैं कंट्रोलर संदर्भ कैसे स्थापित करता हूं। यह contoller पर वास्तविक परीक्षण के लिए सेटअप (परीक्षण इस वर्ग से निकाले जाते हैं) है

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"); 
    }; 
} 

मुझे एहसास है कि यह राइनो मोक्स का उपयोग नहीं करता है। मुझे आशा है कि यह सिद्धांतों को दिखाता है और पाठक इसे अपने विशिष्ट औजारों और तरीकों से अपना सकते हैं।

7

यदि आपको विरासत कोड परीक्षणों के लिए बिल्कुल HttpSessionState को तुरंत चालू करने की आवश्यकता है, तो आप अनियमित वस्तु प्राप्त करने के लिए फॉर्मेटर सर्विसेज तंत्र का लाभ उठा सकते हैं।

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

+0

बहुत बढ़िया। आपने मेरा दिन बचाया (वाई) – Erwin

0

यही तो मैं दूसरों के योगदान के आधार पर बना ...

सार्वजनिक वर्ग: हो यह यह काम कर रहा आंतरिक निर्माता

उदाहरण में निजी _container क्षेत्र स्थापित करने के लिए हालांकि, की तरह की जरूरत है करने के लिए 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]); 


    } 

} 
संबंधित मुद्दे