2011-01-19 19 views
13

के लिए HttpRequest और HttpResponse मॉकिंग मैं वर्तमान में एएसपी एमवीसी अनुप्रयोग की कार्यक्षमता और सही कार्यप्रणाली की जांच करने के लिए कुछ यूनिट परीक्षण लिख रहा हूं। इस एमवीसी अनुप्रयोग में, मैं एक विशेष एक्शनफिल्टर एट्रिब्यूट का उपयोग कर रहा हूं जो एमवीसी अनुप्रयोग के लिए अनुरोध करते समय प्रमाणीकरण की अनुमति देता है।एमवीसी अनुप्रयोग

इस ActionFilterAttribute के लिए कोड यह है:

using System; 
using System.Security.Authentication; 
using System.Text; 
using System.Web.Mvc; 
using TenForce.Execution.Framework; 
using TenForce.Execution.Api2.Implementation; 

namespace TenForce.Execution.Web.Filters 
{ 
    /// <summary> 
    /// This class defines a custom Authentication attribute that can be applied on  controllers. 
    /// This results in authentication occurring on all actions that are beeing defined in the controller 
    /// who implements this filter. 
    /// </summary> 
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] 
    public class AuthenticationFilter : ActionFilterAttribute 
    { 
     #region IAuthorizationFilter Members 

     /// <summary> 
     /// This function get's called by the Mvc framework prior to performing any actions on 
     /// the controller. The function will check if a call is authorized by the caller. 
    /// The function will extract the username and password from the HTTP headers send by 
    /// the caller and will validate these against the database to see if there is a valid 
    /// account for the user. 
    /// If the user can be found in the database, operations will resume, otherwise the action 
    /// is canceled. 
    /// </summary> 
    /// <param name="filterContext">The context for the filter.</param> 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     // Call the base operations first. 
     base.OnActionExecuting(filterContext); 

     // Surround the entire authentication process with a try-catch to prevent errors from 
     // breaking the code. 
     try 
     { 
      // Extract the custom authorization header from the HTTP headers. 
      string customAuthHeader = Encoding.UTF8.GetString(Convert.FromBase64String(filterContext.RequestContext.HttpContext.Request.Headers["TenForce-Auth"])); 

      // Split the header in the subcomponents. 
      string[] components = customAuthHeader.Split('|'); 

      // Check if both components are present. 
      if (components.Length >= 2) 
      { 
       // This header consists of 2 parts, the username and password, seperate by a vertical pipe. 
       string username = components[0] ?? string.Empty; 
       string password = components[1] ?? string.Empty; 
       string databaseId = Authenticator.ConstructDatabaseId(filterContext.HttpContext.Request.RawUrl); 

       // Validate the user against the database. 
       if (Authenticator.Authenticate(username, password, databaseId)) 
       { 
        // The request is valid, so add the custom header to inform the request was 
        // authorized. 
        AllowRequest(filterContext); 
        return; 
       } 

       throw new InvalidCredentialException(@"The provided username & password combination is invalid. Username : " + username); 
      } 

      // If we reach this point, the authorization request is no longer valid. 
      throw new InvalidCredentialException(@"Insufficient parameters supplied for a valid authentication."); 
     } 
     catch (Exception ex) 
     { 
      // Log the exception that has occurred. 
      Logger.Log(GetType(), ex); 

      // Cancel the request, as we could not properly process it. 
      CancelRequest(filterContext); 
     } 
    } 

    #endregion 

    #region Private Methods 

    /// <summary> 
    /// Cancels the Athorization and adds the custom tenforce header to the response to 
    /// inform the caller that his call has been denied. 
    /// </summary> 
    /// <param name="authContext">The authorizationContxt that needs to be canceled.</param>   
    private static void CancelRequest(ActionExecutingContext authContext) 
    { 
     authContext.Result = new HttpUnauthorizedResult(); 
     if (!authContext.RequestContext.HttpContext.Request.ServerVariables[@"SERVER_SOFTWARE"].Contains(@"Microsoft-IIS/7.")) 
      authContext.HttpContext.Response.AddHeader(@"Tenforce-RAuth", @"DENIED"); 
     else 
      authContext.HttpContext.Response.Headers.Add(@"Tenforce-RAuth", @"DENIED"); 
    } 

    /// <summary> 
    /// Allows the Authorization and adds the custom tenforce header to the response to 
    /// inform the claler that his call has been allowed. 
    /// </summary> 
    /// <param name="authContext">The authorizationContext that needs to be allowed.</param> 
    private static void AllowRequest(ActionExecutingContext authContext) 
    { 
     authContext.Result = null; 
     if (!authContext.RequestContext.HttpContext.Request.ServerVariables[@"SERVER_SOFTWARE"].Contains(@"Microsoft-IIS/7.")) 
      authContext.HttpContext.Response.AddHeader(@"Tenforce-RAuth", @"OK"); 
     else 
      authContext.HttpContext.Response.Headers.Add(@"Tenforce-RAuth", @"OK"); 
    }   

    #endregion 
    } 
} 

समस्या मैं वर्तमान का सामना करना पड़ रहा है है कि मैं ठीक से प्रतिक्रिया हेडर के साथ खंड नकली नहीं कर पा रहे। मैंने एक यूनिटटेस्ट लिखा है जो एक HttpRequest और HttpResponse ऑब्जेक्ट को मेल करता है और अनुरोध के साथ विशेषता फ़ंक्शन को कॉल करता है। मैं आईआईएस 7 सिमुलेशन के लिए कोड में सफल लॉगिन पथ शाखा का अनुसरण कर सकता हूं क्योंकि यह गुणों पर निर्भर करता है, लेकिन जब मैं लॉगिन में आईआईएस 6 शाखा का पालन करने का प्रयास करता हूं, तो मुझे शून्य सूचक अपवाद मिल रहा है।

मैं MOQ वस्तुओं का निर्माण करने के लिए निम्न कोड का उपयोग करें:

/// <summary> 
    /// This function is called before running each test and configures the various properties 
    /// of the test class so that each test will run with the same settings initialy. 
    /// The function will configure the Mock Framework object so that they simulate a proper 
    /// web request on the ActionFilter of a Controller. 
    /// </summary> 
    [SetUp] 
    protected void TestSetup() 
    { 
     // Construct the Mock object required for the test. 
     HttpRequest = new Mock<HttpRequestBase>(); 
     HttpResponse = new Mock<HttpResponseBase>(); 
     HttpContext = new Mock<HttpContextBase>(); 
     ActionContext = new Mock<ActionExecutingContext>(); 
     Filter = new Web.Filters.AuthenticationFilter(); 

     // Configure the properties to modify the headers, request and response 
     // objects starting from the HttpContext base object. 
     // Also create the custom header collection and set the test URI. 
     ActionContext.SetupGet(c => c.HttpContext).Returns(HttpContext.Object); 
     HttpContext.SetupGet(r => r.Request).Returns(HttpRequest.Object); 
     HttpContext.SetupGet(r => r.Response).Returns(HttpResponse.Object); 
     HttpResponse.SetupGet(x => x.Headers).Returns(new System.Net.WebHeaderCollection()); 
     HttpRequest.SetupGet(r => r.RawUrl).Returns(@"http://test.tenforce.tst"); 
    } 

actuall परीक्षण इस तरह दिखता है: क्योंकि हैडर beeing सेट नहीं है

/// <summary> 
    /// <para>This test will call the ActionFilter and perform a standard authorization request against the 
    /// database using the credentials of the system administrator account. The test relies on the MoQ 
    /// framework to mock several of the key components in the MVC Framework such as the HttpRequest, 
    /// HttpResponse and HttpContext objects.</para> 
    /// <para>The test expects the authentication to succeed, and relies on the IIS6 implementation.</para> 
    /// </summary> 
    [Test, MaxDuration] 
    public void SuccessfullAuthenticationOnIis6() 
    { 
     // Configure the Authentication header of the request, so that a valid authentication 
     // can take place. We want valid login credentials when the filter requests the header. 
     HttpRequest.SetupGet(r => r.Headers).Returns(new System.Net.WebHeaderCollection { { @"TenForce-Auth", CorrectAuthToken } }); 
     HttpRequest.SetupGet(r => r.ServerVariables).Returns(
      new System.Collections.Specialized.NameValueCollection { { @"SERVER_SOFTWARE", @"Microsoft-IIS/6.0" } }); 
     HttpResponse.SetupGet(r => r.Headers).Returns(new System.Collections.Specialized.NameValueCollection()); 
     HttpResponse.Setup(r => r.AddHeader(@"TenForce-RAuth", @"OK")); 

     // Call the action on the filter and check the response. 
     Filter.OnActionExecuting(ActionContext.Object); 

     // Check the ActionResult to null and that the response header contains the correct value. 
     Assert.IsTrue(ActionContext.Object.Result == null); 
     Assert.IsTrue(ActionContext.Object.HttpContext.Response.Headers["TenForce-RAuth"].Equals(@"OK")); 
    } 

पिछले ज़ोर विफल हो रहा है। मैंने कोड के माध्यम से कदम उठाने के लिए डीबगर का उपयोग किया है और फ़िल्टर वास्तव में हेडर सेट करता है, इसलिए मुझे लगता है कि अनुरोध को संभालने के लिए MoQ ऑब्जेक्ट ठीक से कॉन्फ़िगर नहीं किया गया है।

क्या कोई इस बात पर कुछ प्रकाश डाल सकता है कि मैं हेडर्स को स्वीकार करने के लिए कैसे अपना एचटीपीआरपीएस प्राप्त कर सकता हूं। (अनुरोध) जोड़ें?

+0

क्या मजाक ढांचे आप के लिए उपयोग किया था ये परीक्षण? –

+0

शायद देर से रास्ता, लेकिन हम NUnit का इस्तेमाल किया –

उत्तर

9

ऐसा लगता है कि मैंने इसे पाया है। मैं कार्यान्वयन के लिए MOQ की कॉल को सौंपने के लिए मेरी सेटअप करने के लिए निम्न पंक्ति जोड़ने के लिए किया था:

HttpResponse.Setup(r => r.AddHeader(It.IsAny<string>(), It.IsAny<string>())).Callback<string, string>((x,y) => HttpResponse.Object.Headers.Add(x, y)); 

बल्कि आसान है, लेकिन आप यह जानना है ...

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