我已经编写了自定义声明授权属性,我想对我编写的代码进行单元测试,但无法找到我在SO上寻找的内容。
例如,这是我的自定义授权属性类:
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using IPD2.MVC.Interfaces.Providers;
using IPD2.MVC.Providers;
namespace IPD2.MVC.Attribute
{
public class ClaimsAuthorizeAttribute : AuthorizeAttribute
{
private readonly string _claimValue;
private readonly string _claimType;
private readonly ITokenProvider _tokenProvider;
public ClaimsAuthorizeAttribute(string type, string value)
{
_claimType = type;
_claimValue = value;
_tokenProvider = new TokenProvider();
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
var jwt = _tokenProvider.ApiToken as JwtSecurityToken;
if (jwt == null)
{
HandleUnauthorizedRequest(filterContext);
}
else
{
var claim = jwt.Claims.FirstOrDefault(expr => expr.Value == _claimValue);
var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
var formsAuthenticationTicket = FormsAuthentication.Decrypt(authCookie.Value);
if (formsAuthenticationTicket != null && !formsAuthenticationTicket.Expired)
{
var roles = formsAuthenticationTicket.UserData.Split(',');
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(formsAuthenticationTicket), roles);
}
}
if (claim != null)
{
base.OnAuthorization(filterContext);
}
else
{
HandleUnauthorizedRequest(filterContext);
}
}
}
}
}
测试代码
public class GivenCallingClaimAuthorizationAttribute : SpecsFor<ClaimsAuthorizeAttribute>
{
//HttpActionContext actionContext;
//IPrincipal originalPrincipal;
protected override void Given()
{
SUT = new ClaimsAuthorizeAttribute(ClaimTypes.Role, "ImNotAllowedToUseController :(");
}
public class WhenUserIsNotAllowedToAccessController : GivenCallingClaimAuthorizationAttribute
{
protected override void When()
{
SUT.OnAuthorization(
new AuthorizationContext()
);
}
}
[Test]
public void ThenAssertSomethingBasedOnCodeInTest()
{
//todo: some assert
}
}
我已经使用SpecsFor BDD框架编写了这个基本测试类,但我不确定它成功测试它需要什么。
关于如何测试这个的任何想法?如您所见,我正在测试类本身,而不是具有该属性的控制器。我不确定测试它的好方法。
答案 0 :(得分:0)
如果你想做BDD,请考虑你班级的行为。应该做什么样的事情?
例如,也许它应该:
- 授权当前用户
- 过滤机票已过期的用户
- 为授权用户分配正确的角色
- 等等。
让我们说我们要看第二个,因为它很有趣。我会问你,“你能告诉我一张票何时到期的例子吗?”
你说,“是的,超时时间是500毫秒,所以任何比这更早的东西都过期了。”或者你说,“这些是足球比赛的门票,每年都会发出。” (我不知道票是什么,但这次谈话会帮助我解决这个问题。)
那么我们可以写一个例子:
Given we've got a handler for unauthorized tickets
Given Fred's ticket expired on 2017-05-14
And it's now 2017-05-14
When we try to authenticate Fred
Then Fred should not be authenticated
And the handler should be given Fred's details
接下来我喜欢将这些放在代码中的注释中,并将“should”作为测试的标题。之后,只需设置上下文(在Given中),将其传递给您的代码进行练习(When)并验证结果(Then)。
但是,您可以看到您的Specs框架仅允许一个给定的!这不是很好,因为我已经确定了几个需要不同背景的场景。如果你使用SpecsFor就像你使用它一样,你必须为我的每个场景制作一个类,并且它们不会很容易阅读!
我强烈建议使用第二种风格,然后在评论中开始使用Given,When,Then。
事实上,与全系统BDD场景相比,单元测试的步骤并没有真正重复使用,在这种情况下,不同功能通常会多次调用上下文。代码(或类)的单元倾向于履行一个责任,或者它以这种方式被重构,并且它的上下文不会因为Mocks而流入其他类。所以,我发现在评论中只有Give,When和Then就足够了。
因此,我建议您切换到“旧学校”的做事方式,我可以在此页面中看到(从下到下),然后从评论开始。看看这对你有什么用。
顺便说一句,如果你真的想要正确地做BDD,那么你想用它的行为示例驱动开发,并逐步填写代码以使这些例子有效,而不是写下来。这本书"Growing Object Oriented Software, Guided By Tests"对你很有帮助。