1

我想测试一个在某些时候使用一些 HttpModule 的控制器方法(ASP.NET MVC 4),如下所示:

 var sessionToken = CreateSessionSecurityToken(CreatePrincipal(claims.ToList()), isPersistent);
            FederatedAuthentication.**SessionAuthenticationModule**.WriteSessionTokenToCookie(sessionToken);

该模块是 SessionAuthenticationModule 的子类。我在测试程序集的 app.config 文件中有必要的配置:

<system.web>
    <httpModules>
      <remove name="FormsAuthentication" />
      <add name="FormsSessionAuthentication" type="Security.FormsSessionAuthenticationModule, Security"/>
      <!--<add name="SessionAuthenticationModule"
           type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />-->
    </httpModules>
...

 <system.webServer>

    <validation validateIntegratedModeConfiguration="false" />

    <modules runAllManagedModulesForAllRequests="true" >
      <remove name="FormsAuthentication" />
      <add name="FormsSessionAuthentication" type="Security.FormsSessionAuthenticationModule, Security"/>
      <!--<add name="SessionAuthenticationModule"
           type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />-->
    </modules>

这就是我试图从单元测试上下文中做的事情:

            HttpContext.Current.ApplicationInstance = new HttpApplication();
            HttpApplication.RegisterModule(typeof (FormsSessionAuthenticationModule));
            Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(FormsSessionAuthenticationModule));

            var modules = HttpContext.Current.ApplicationInstance.Modules;

modules我尝试使用上述两种方法注册后,该集合为空。

有任何想法吗?

编辑 - 添加了 httpModule 实现

public class FormsSessionAuthenticationModule : SessionAuthenticationModule
{
    protected bool IsSlidingExpiration { get; set; }
    protected TimeSpan Timeout { get; set; }
    protected string LoginUrl { get; set; }
    protected string CookieName { get; set; }
    protected string CookieDomain { get; set; }
    protected bool RequireSsl { get; set; }
    protected bool CachePrincipalOnServer { get; set; }

    protected override void InitializeModule(HttpApplication context)
    {
        base.InitializeModule(context);

        context.EndRequest += OnEndRequest;
    }

    protected override void InitializePropertiesFromConfiguration()
    {
        base.InitializePropertiesFromConfiguration();

        // read formsauth configuration
        IsSlidingExpiration = FormsAuthentication.SlidingExpiration;
        Timeout = FormsAuthentication.Timeout;
        LoginUrl = FormsAuthentication.LoginUrl;
        CookieName = FormsAuthentication.FormsCookieName;
        CookieDomain = FormsAuthentication.CookieDomain;
        RequireSsl = FormsAuthentication.RequireSSL;

        // read other configuration
        CachePrincipalOnServer = false;
        bool enabled;
        if (bool.TryParse(ConfigurationManager.AppSettings["CachePrincipalOnServer"], out enabled))
        {
            CachePrincipalOnServer = enabled;
        }

        // configure cookie handler
        CookieHandler.Name = CookieName;
        CookieHandler.Domain = CookieDomain;
        CookieHandler.RequireSsl = RequireSsl;
    }

    protected override void OnSessionSecurityTokenReceived(SessionSecurityTokenReceivedEventArgs e)
    {
        base.OnSessionSecurityTokenReceived(e);

        if (IsSlidingExpiration)
        {
            if (NeedsRenew(e.SessionToken))
            {
                e.SessionToken = CreateSessionSecurityToken(
                    e.SessionToken.ClaimsPrincipal,
                    e.SessionToken.Context,
                    DateTime.UtcNow,
                    DateTime.UtcNow.Add(Timeout),
                    e.SessionToken.IsPersistent);

                e.SessionToken.IsReferenceMode = CachePrincipalOnServer;
                e.ReissueCookie = true;
            }
        }
    }

    private void OnEndRequest(object sender, EventArgs e)
    {
        var httpApplication = sender as HttpApplication;
        if (httpApplication != null)
        {
            var context = httpApplication.Context;

            if (context.Response.StatusCode == 401)
            {
                var noRedirect = context.Items["NoRedirect"];

                if (noRedirect == null)
                {
                    var loginUrl = LoginUrl + "?returnUrl=" + HttpUtility.UrlEncode(context.Request.RawUrl, context.Request.ContentEncoding);
                    context.Response.Redirect(loginUrl);
                }
            }
        }
    }

    protected virtual bool NeedsRenew(SessionSecurityToken token)
    {
        DateTime utcNow = DateTime.UtcNow;

        TimeSpan span = utcNow - token.ValidFrom;
        TimeSpan span2 = token.ValidTo - utcNow;

        if (span2 > span)
        {
            return false;
        }

        return true;
    }
}
4

1 回答 1

-1

你不应该这样做:)

您更好的选择是围绕模块创建一个包装器。并将您的包装器注入控制器中。这样您就可以在测试中模拟包装器。

public interface IAuthModule
{
   void WriteSessionTokenToCookie(Token sessionToken);
}

public class MyAuthModuleWrapper : IAuthModule
{
   public void WriteSessionTokenToCookie(Token sessionToken)
   {
       FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);
   }
}

然后,如果你不使用 IoC 容器来连接你的应用程序,你可以为你的控制器使用穷人的 man 版本(我强烈建议使用 IoC):

public class MyController : Controller
{
   private readonly IAuthModule _authModule;

   public MyController() : this(new MyAuthModuleWrapper()){}

   public MyController(IAuthModule authModule)
   {
      _authModule = authModule;
   }

   public ActionResult MyTestAction(string data)
   {
        // ... do whatever is here
        var sessionToken = CreateSessionSecurityToken(CreatePrincipal(claims.ToList()), isPersistent);
        _authModule.WriteSessionTokenToCookie(sessionToken);
        // ... do whatever else
   }
}

然后,在您的测试中,您可以使用任何模拟框架,或者如果您不想这样做,您可以为 IAuthToken 创建自己的存根,它的行为就像您希望它的行为一样,并使用它来构建您的控制器。

而且......你都准备好了。您可以在不依赖第三方模块注册的情况下测试您的控制器。

于 2013-09-27T21:50:43.927 回答