2011-01-19 27 views
13

私は現在、私たちが作成したASP MVCアプリケーションの機能と正しい動作をチェックするためにいくつかの単体テストを書いています。 このMVCアプリケーションでは、特別なActionFilterAttributeを使用して、MVCアプリケーションにリクエストを行う際の認証を許可しています。MVCアプリケーションの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オブジェクトをモックし、要求と共に属性関数を呼び出すUnitTestを作成しました。これはプロパティに依存するので、私はIIS7シミュレーションのコードで成功したログインパスブランチに従うことができますが、ログイン時にIIS6ブランチに従おうとすると、NULLポインタ例外が発生します。

Iは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オブジェクトが要求を処理するように正しく構成されていないと思います。

誰かが、HttpResponseでHeaders.Add()リクエストを受け付ける方法を理解できますか?

+0

:私は実装にMOQの呼び出しを委任するために私のセットアップに次の行を追加する必要がありましたこれらのテスト? –

+0

おそらく遅くまで、私たちはNUnitを使用しました –

答えて

9

私はそれを見つけたようです。

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

むしろシンプルですが、あなたはそれを知っている必要があります...あなたがのために使用しました何モッキングフレームワーク

関連する問題