Asp.net-Mvc

Request.GetOwinContext 在單元測試中返回 null - 如何在單元測試中測試 OWIN 身份驗證?

  • July 19, 2014

我目前正在嘗試對我正在編寫的使用 OWIN 進行身份驗證的新 WebAPI 項目的身份驗證進行單元測試,並且在單元測試上下文中執行它時遇到問題。

這是我的測試方法:

[TestMethod]
public void TestRegister()
{
   using (WebApp.Start<Startup>("localhost/myAPI"))
   using (AccountController ac = new AccountController()
       {
           Request = new System.Net.Http.HttpRequestMessage
               (HttpMethod.Post, "http://localhost/myAPI/api/Account/Register")
       })
   {
       var result = ac.Register(new Models.RegisterBindingModel()
       {
           Email = "testemail@testemail.com",
           Password = "Pass@word1",
           ConfirmPassword = "Pass@word1"
       }).Result;
       Assert.IsNotNull(result);
   }
}

我正在獲得AggregateException以下.Result內部異常:

Result Message: 
Test method myAPI.Tests.Controllers.AccountControllerTest.TestRegister 
   threw exception: 
System.ArgumentNullException: Value cannot be null.
Parameter name: context
Result StackTrace:  
at Microsoft.AspNet.Identity.Owin.OwinContextExtensions
   .GetUserManager[TManager](IOwinContext context)
at myAPI.Controllers.AccountController.get_UserManager()
...

我已經通過調試確認Startup正在呼叫我的方法,呼叫ConfigurAuth

public void ConfigureAuth(IAppBuilder app)
{
   HttpConfiguration config = new HttpConfiguration();
   config.MapHttpAttributeRoutes();
   app.UseWebApi(config);

   // Configure the db context and user manager to use a single 
   //  instance per request
   app.CreatePerOwinContext(ApplicationDbContext.Create);
   app.CreatePerOwinContext<ApplicationUserManager>
       (ApplicationUserManager.Create);

   // Enable the application to use a cookie to store information for 
   //  the signed in user
   //  and to use a cookie to temporarily store information about a 
   //  user logging in with a third party login provider
   app.UseCookieAuthentication(new CookieAuthenticationOptions());
   app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

   // Configure the application for OAuth based flow
   PublicClientId = "self";
   OAuthOptions = new OAuthAuthorizationServerOptions
   {
       TokenEndpointPath = new PathString("/Token"),
       Provider = new ApplicationOAuthProvider(PublicClientId),
       AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
       AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
       AllowInsecureHttp = true
   };

   // Enable the application to use bearer tokens to authenticate users
   app.UseOAuthBearerTokens(OAuthOptions);
}

我嘗試了一些東西,但似乎沒有任何效果 - 我永遠無法獲得 OWIN 上下文。測試在以下程式碼上失敗:

// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
   if (!ModelState.IsValid)
   {
       return BadRequest(ModelState);
   }

   var user = new ApplicationUser() 
      { UserName = model.Email, Email = model.Email };

   IdentityResult result = await UserManager.CreateAsync(user, model.Password);

   if (!result.Succeeded)
   {
       return GetErrorResult(result);
   }

   return Ok();
}

這呼叫了UserManager屬性:

public ApplicationUserManager UserManager
{
   get
   {
       return _userManager ?? Request.GetOwinContext()
          .GetUserManager<ApplicationUserManager>();
   }
   private set
   {
       _userManager = value;
   }
}

它失敗了:

return _userManager ?? Request.GetOwinContext()
   .GetUserManager<ApplicationUserManager>();

帶有NullReferenceException-Request.GetOwinContext正在返回null

所以我的問題是:我接近這個錯誤嗎?我應該只測試 JSON 響應嗎?還是有一種“內部”測試 OWIN 身份驗證的好方法?

GetOwinContext 呼叫 context.GetOwinEnvironment(); 這是

 private static IDictionary<string, object> GetOwinEnvironment(this HttpContextBase context)
   {
       return (IDictionary<string, object>) context.Items[HttpContextItemKeys.OwinEnvironmentKey];
   }

和 HttpContextItemKeys.OwinEnvironmentKey 是一個常量“owin.Environment”所以如果你在你的 httpcontext 的項目中添加它,它會起作用。

var request = new HttpRequest("", "http://google.com", "rUrl=http://www.google.com")
   {
       ContentEncoding = Encoding.UTF8  //UrlDecode needs this to be set
   };

   var ctx = new HttpContext(request, new HttpResponse(new StringWriter()));

   //Session need to be set
   var sessionContainer = new HttpSessionStateContainer("id", new SessionStateItemCollection(),
       new HttpStaticObjectsCollection(), 10, true,
       HttpCookieMode.AutoDetect,
       SessionStateMode.InProc, false);
   //this adds aspnet session
   ctx.Items["AspSession"] = typeof(HttpSessionState).GetConstructor(
       BindingFlags.NonPublic | BindingFlags.Instance,
       null, CallingConventions.Standard,
       new[] { typeof(HttpSessionStateContainer) },
       null)
       .Invoke(new object[] { sessionContainer });

   var data = new Dictionary<string, object>()
   {
       {"a", "b"} // fake whatever  you need here.
   };

   ctx.Items["owin.Environment"] = data;

引用自:https://stackoverflow.com/questions/24836845