2010-10-26 3 views
14

मैं एक वेब सेवा के लिए यूनिट परीक्षण लिखना चाहता हूं। मैं अपना परीक्षण प्रोजेक्ट बनाता हूं, मेरा वेब प्रोजेक्ट संदर्भित करता हूं (सेवा संदर्भ, असेंबली संदर्भ नहीं), फिर वेब सेवाओं का परीक्षण करने के लिए कुछ कोड लिखें - वे ठीक काम करते हैं। हालांकि, कुछ सेवाएं हैं जो सुनिश्चित करती हैं कि उपयोगकर्ता HttpContext.Current.User.Identity.IsAuthenticated का उपयोग करके वेब एप्लिकेशन में लॉग इन है।यूनिट परीक्षण वेब सेवाएं - HttpContext

परीक्षणों के संदर्भ में, HttpContext जैसी कोई चीज़ नहीं है, इसलिए परीक्षण हमेशा विफल हो जाते हैं। इन प्रकार की वेब सेवाओं को यूनिट का परीक्षण कैसे किया जाना चाहिए?

उत्तर

25

Here एक संबंधित चर्चा है।

मैंने सीधे HttpContext.Current का संदर्भ देना बंद कर दिया। और इस वर्ग के बजाय का उपयोग करें:

public class HttpContextFactory 
{ 
    private static HttpContextBase m_context; 
    public static HttpContextBase Current 
    { 
     get 
     { 
      if (m_context != null) 
       return m_context; 

      if (HttpContext.Current == null) 
       throw new InvalidOperationException("HttpContext not available"); 

      return new HttpContextWrapper(HttpContext.Current); 
     } 
    } 

    public static void SetCurrentContext(HttpContextBase context) 
    { 
     m_context = context; 
    } 
} 

और हमारे कोड में HttpContextFactory.Current बजाय HttpContext.Current का उपयोग करें।

तो फिर आप अपने परीक्षण में यह लिख:

 HttpContextFactory.SetCurrentContext(GetMockedHttpContext()); 

जहां GetMockedHttpContext() here से है और इस तरह दिखता है:

private System.Web.HttpContextBase GetMockedHttpContext() 
    { 
     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>(); 

     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); 
     user.Setup(x => x.Identity).Returns(identity.Object); 
     identity.Setup(id => id.IsAuthenticated).Returns(true); 
     identity.Setup(id => id.Name).Returns("test"); 

     return context.Object; 
    } 

यह एक mocking frameworkmoq

कहा जाता है का उपयोग करता है अपने परीक्षण परियोजना आपको System.Web और System.Web.Abstractions का संदर्भ जोड़ना है, जहां HttpContextBase परिभाषित किया गया है।

+0

मैंने यह भी करना शुरू कर दिया है (HttpContext को HttpContextFactory के साथ बदलना), और यह वास्तव में यूनिट परीक्षण के साथ मदद करता है (मैंने इस क्षमताओं को एक एपीआई में लपेट लिया है जिसे आप यहां देख सकते हैं http://o2platform.wordpress.com/2011/ 04/05/मॉकिंग-httpcontext-httprequest-and-httpresponse-for-unittests-use-moq /) –

+1

मैं moq का उपयोग नहीं कर रहा हूं, इसलिए यह मुझे 100% तक नहीं मिला, लेकिन यह सहायक था। मैंने सहायता के लिए स्टीफन वाल्थर की नकली वस्तुओं को देखा: http://stephenwalther.com/archive/2008/07/01/asp-net-mvc-tip-12-faking-the-controller-context.aspx –

2

आप मजाक का उपयोग कर रहे हैं, तो आप एक और कक्षा में इस तर्क लपेट कर सकते हैं:

interface IAuthenticator 
{ 
    bool IsAuthenticated(); 
} 

और लागू असली:

class Authenticator : IAuthenticator 
{ 
    bool IsAuthenticated() 
    { 
     return HttpContext.Current.User.Identity.IsAuthenticated; 
    } 
} 

लेकिन परीक्षण में, एक नकली बना सकते हैं और सच वापसी या गलत:

Mock<IAuthenticator> mock = new Mock<IAuthenticator>(); 
mock.Expect(x => x.IsAuthenticated()).Returns(true); 
+0

बिल्कुल सही होने के लिए मुझे लगता है कि यह वास्तव में एक स्टब होना चाहिए और नकली नहीं होना चाहिए। –

+0

क्या आपका मतलब है कि हमें नकली के बजाय स्टब की आवश्यकता है? मैं असहमत हूं क्योंकि प्रमाणीकृत या नहीं, सेवा अलग-अलग व्यवहार करेगी इसलिए हमें वापस आने में सक्षम होने की उम्मीद की आवश्यकता है। मुझे यकीन नहीं है - और वह उत्सुक नहीं है - एक स्टब और नकली के मतभेदों पर, लेकिन मेरे लिए, यह एक नकली है और स्टब नहीं है। – Aliostad

+0

यदि इरादा यह जांचना है कि IAuthenticator इंटरफ़ेस सही ढंग से कहा जाता है तो यह एक नकली होना चाहिए। यदि आप किसी और चीज का परीक्षण करना चाहते हैं तो यह एक स्टब होना चाहिए। स्टब्स कभी भी परीक्षण विफल होने का कारण नहीं बनेंगे। वे चीजों को आसानी से चलाने के लिए बस वहां हैं। वैसे भी मुझे लगता है कि यह आपके मॉकिंग ढांचे पर निर्भर करता है। राइनो मोक्स में मोक्स और स्टब्स के बीच एक सूक्ष्म अंतर होता है: http://stackoverflow.com/questions/463707/what-are-the-differences-between-mocks-and-stubs-on-rhino-mocks –

1

आप यू के बजाय System.Web.Abstractions.HttpContextBase पर निर्भरता लेने पर विचार हो सकता है HttpContext.Current गाओ। System.Web.Abstractions असेंबली में आपके लिए पहले से लपेटा गया बहुत आम एएसपी.नेट एचटीपी * वर्ग है। वे सभी एएसपी.नेट एमवीसी कोड पर उपयोग किया जाता है। यदि आप आईओसी/डी फ्रेमवर्क का उपयोग कर रहे हैं, तो इसका उपयोग करना बहुत आसान है। उदाहरण के लिए, Ninject में:

Bind<HttpContextBase>.ToMethod(x => new HttpContextWrapper(HttpContext.Current)); 

और फिर अपने निर्माता में ...

public class SomeWebService 
{ 
    private HttpContextBase _httpContext; 

    public SomeWebService(HttpContextBase httpContext) 
    { 
     _httpContext = httpContext; 
    } 

    public void SomeOperationNeedingAuthorization() 
    { 
     IIdentity userIdentity = _httpContext.User.Identity; 

     if (!userIdentity.IsAuthenticated) 
      return; 

     // Do something here... 
    } 
} 

कि जिस तरह से oversimplified है, लेकिन मुझे आशा है कि आप विचार प्राप्त ... Aliostad उल्लेख किया है, तो आप आसानी से नकली कर सकते हैं कुछ ऑपरेशन न्यूडिंग प्राधिकरण का परीक्षण करने के लिए राइनो मोक्स या मोक इत्यादि का उपयोग करके एचटीपी कॉनटेक्स्टबेस।

+0

आप भी हो सकते हैं एक वाणिज्यिक मॉकिंग टूल, जैसे कि टाइपपेक आइसोलेटर या टेलीरिक के जस्टमैक का उपयोग करने पर विचार करें, जो एचटीपी * एब्स्ट्रैक्शन का उपयोग/प्रबंधन करने से कम है। –

0

मैं वेब सेवा पर एक संपत्ति डाल समाप्त हो गया:

Private mIdentity As System.Security.Principal.IIdentity 
Public Property Identity() As System.Security.Principal.IIdentity 
    Get 
    If mIdentity Is Nothing Then mIdentity = HttpContext.Current.User.Identity 
    Return mIdentity 
    End Get 
    Set(ByVal value As System.Security.Principal.IIdentity) 
    mIdentity = value 
    End Set 
End Property 
तब मेरे वेब सेवा विधि में

:

<WebMethod()> _ 
Public Function GetProject(ByVal projectId As Int32) As String 

    If Me.Identity.IsAuthenticated Then 

    'code here 

    End If 

End Function 
फिर अपने परीक्षण (मैं RhinoMocks उपयोग कर रहा हूँ) में

:

Dim mockery As New MockRepository() 
Dim mockIdentity As System.Security.Principal.IIdentity = mockery.DynamicMock(Of System.Security.Principal.IIdentity)() 

Dim projectService As New TeamDynamix.Enterprise.Web.Next.ProjectService() 
projectService.Identity = mockIdentity 
mockIdentity.Stub(Function(i As System.Security.Principal.IIdentity) i.IsAuthenticated).Return(True) 
0

समाधान ऊपर, मैं O2 Platform कि इन मजाक वर्गों के आसान उपयोग की अनुमति देता में एक आवरण वर्ग को क्रियान्वित किया है, उदाहरण के लिए यह कैसे मैं लिख सकते हैं और HttpRequest.InputStream से पढ़ सकते हैं, इसके आधार पर

var mockHttpContext = new API_Moq_HttpContext(); 
var httpContext = mockHttpContext.httpContext(); 
httpContext.request_Write("<html><body>".line()); 
httpContext.request_Write(" this is a web page".line()); 
httpContext.request_Write("</body></html>"); 
return httpContext.request_Read(); 

अधिक जानकारी के लिए इस ब्लॉग पोस्ट को देखें: http://o2platform.wordpress.com/2011/04/05/mocking-httpcontext-httprequest-and-httpresponse-for-unittests-using-moq/