Mocking HttpRequest et HttpResponse pour l'application MVC

Je suis actuellement à l'écriture de tests unitaires pour vérifier la fonctionnalité et le correct fonctionnement de l'ASP MVC de l'application que nous avons écrit.
Dans cette Application MVC, je suis en utilisant un spécial ActionFilterAttribute qui permet pour l'authentification lors de la demande de l'Application MVC.

Le code de cette ActionFilterAttribute est-ce:

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
}
}

Le problème, je suis actuellement confrontés est que je n'arrive pas à correctement se moquer de la section avec les en-têtes de réponse. J'ai écrit un UnitTest qui se moque d'un HttpRequest et objet HttpResponse et appelle l'attribut fonction de la demande. Je peux suivre la connexion réussie, chemin de la branche dans le code d'une IIS7 simulation comme cela repose sur des propriétés, mais quand j'essaye de suivre la IIS6 branche dans une connexion, je suis de pointeur null exceptions.

J'utilise le code suivant pour construire le MoQ objets:

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

La actuall test ressemble à ceci:

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

La dernière assertion échoue parce que l'en-tête n'est pas en étant ensemble. J'ai utilisé le débogueur à l'étape dans le code et le filtre ne fait la tête, donc je pense que le MoQ objet n'est pas correctement configuré pour traiter la demande.

Quelqu'un pourrait s'il vous plaît faire la lumière sur la manière d'obtenir mon HttpResponse à accepter les en-Têtes.Ajouter() demande?

source d'informationauteur coding-bunny