我目前正在尝试使用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);
}
}
我在获取.Result
时得到了一个AggregateException
,但有以下内部异常:
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身份验证的好方法?
发布于 2015-12-16 02:17:09
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;
发布于 2015-11-03 02:30:16
为了确保OWIN上下文在测试期间可用(即,修复调用Request.GetOwinContext()
时的空引用异常),您需要在测试项目中安装Microsoft.AspNet.WebApi.Owin
NuGet包。安装完成后,您可以对请求使用SetOwinContext
扩展方法。
示例:
var controller = new MyController();
controller.Request = new HttpRequestMessage(HttpMethod.Post,
new Uri("api/data/validate", UriKind.Relative)
);
controller.Request.SetOwinContext(new OwinContext());
也就是说,我同意针对您的特定用例的其他答案--在构造函数中提供一个AppplicationUserManager实例或工厂。如果您需要直接与测试将使用的上下文进行交互,则上述SetOwinContext
步骤是必要的。
发布于 2014-07-22 04:32:51
您可以只在AccountController的构造函数中传入UserManager,这样它就不会试图在owinContext中找到它。默认构造函数对单元测试不友好。
https://stackoverflow.com/questions/24836845
复制相似问题