我正在尝试单元测试我正在使用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() ...
我已经通过调试确认我的启动方法正在被调用,调用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(); }
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;