Asp.net-Mvc
Request.GetOwinContext 在單元測試中返回 null - 如何在單元測試中測試 OWIN 身份驗證?
我目前正在嘗試對我正在編寫的使用 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;