使用集成测试Web Api

所以我发现在[Authorize]标签上有些东西让我有所启发,但没有什么可以解决我的问题。

我的场景是我有Web Api方法,我希望使用RestSharp进行集成测试。 但是,RestSharp正在获取我的登录页面,而不是调用的结果。

[Authorize] public Item GetItem([FromBody] int id) { return service.GetItem(id); } 

该产品使用自定义登录系统,我真正想要的是一种只为集成测试禁用[授权]徽章的方法。 但是我读到你可以允许匿名用户,它会“禁用”徽章,所以在解决方案中,我有一个集成测试项目,在那个项目中我有一个App.config文件。 在那个文件中,我把:

         

但这似乎也不起作用。 任何有关正在发生的事情的解释,为什么它不起作用以及如何才能使这项工作将不胜感激。

我试图设置一个Thread.CurrentPrincipal但是没有用(也许我做错了 – 你能在代码中设置“任何”授权吗?)。 如果有帮助,则在httpmodule中处理身份validation。

以下是设置Thread.CurrentPrincipal 。 将这样的消息处理程序添加到Web API项目中,并在WebApiConfig.csRegister方法中添加处理程序, WebApiConfig.cs所示: config.MessageHandlers.Add(new MyTestHandler());

 public class MyTestHandler : DelegatingHandler { protected override async Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { var local = request.Properties["MS_IsLocal"] as Lazy; bool isLocal = local != null && local.Value; if (isLocal) { if (request.Headers.GetValues("X-Testing").First().Equals("true")) { var dummyPrincipal = new GenericPrincipal( new GenericIdentity("dummy", "dummy"), new[] { "myrole1" }); Thread.CurrentPrincipal = dummyPrincipal; if (HttpContext.Current != null) HttpContext.Current.User = dummyPrincipal; } } return await base.SendAsync(request, cancellationToken); } } 

此处理程序设置经过身份validation的主体,以使您的所有[Authorize]满意。 这种方法存在风险因素。 仅用于测试,您应该将此处理程序插入Web API管道。 如果您将此处理程序插入生产代码中的管道(有意或无意),它基本上会破坏您的身份validation机制。 为了在某​​种程度上降低风险(希望API不在本地访问),我检查以确保访问是本地的,并且有一个标题X-Testing ,其值为true

从RestSharp中,添加自定义标头。

 var request = new RestRequest(...); request.AddHeader("X-Testing", "true"); 

顺便说一下,对于集成测试,我宁愿使用内存托管,而不是网络托管。 这样,Web API就可以在同一个测试项目中运行,您可以随心所欲地使用它,而不必担心会破坏生产中的某些内容。 有关内存中托管的更多信息,请参阅此内容 。

我意识到这个问题是关于在webapi端点触发RestSharp的“真实”请求,所以这个建议不能立即适用于OP场景。但是:

我正在使用HttpConfigurationHttpServerHttpMessageInvoker进行内存中的Web Api测试(很像Badri的建议,我相信)。 通过这种方式,我不需要监听器或端口打开,因为我可以在内存中测试完整的堆栈(端到端测试) – 在构建服务器,Heroku实例等上非常方便。

使用内存中的测试,这里是你如何设置Thread.CurrentPrincipal ..我在我的测试基类上有一个帮助器,如下所示:

 protected void AuthentateRequest() { Thread.CurrentPrincipal = new AuthenticatedPrincipal(Thread.CurrentPrincipal); } 

哪个使用这个:

 public class AuthenticatedPrincipal : IPrincipal { private readonly IPrincipal _principalToWrap; private readonly IIdentity _identityToWrap; public AuthenticatedPrincipal(IPrincipal principalToWrap) { _principalToWrap = principalToWrap; _identityToWrap = new AuthenticatedIdentity(principalToWrap.Identity); } public bool IsInRole(string role) { return _principalToWrap.IsInRole(role); } public IIdentity Identity { get { return _identityToWrap; } private set { throw new NotSupportedException(); } } } public class AuthenticatedIdentity : IIdentity { private readonly IIdentity _identityToWrap; public AuthenticatedIdentity(IIdentity identityToWrap) { _identityToWrap = identityToWrap; } public string Name { get { return _identityToWrap.Name; } private set { throw new NotSupportedException(); } } public string AuthenticationType { get { return _identityToWrap.AuthenticationType; } private set { throw new NotSupportedException(); } } public bool IsAuthenticated { get { return true; } private set { throw new NotSupportedException(); } } } 

手动存根IPrincipal似乎有些过分但我尝试使用我的模拟框架并且它在我的一些测试运行器(Resharper和TeamCity,但不是NCrunch – 我认为关于在AppDomains上进行序列化的事情)中爆炸了。

这将在ApiController操作方法中设置Thread.CurrentPrincipal ,因此欺骗AuthorizeAttribute使您相信您已通过身份validation。

设置RestClient的身份validationRestClient

 RestClient.Authenticator = new HttpBasicAuthenticator(username, password); 

使用您的自定义登录系统实际接受的身份validation器… Basic,NTLM,OAuth,Simple …

在http://restsharp.org/的示例的第二行中记录了这种情况。