如何在 ASP.NET Core 中测试自定义操作过滤器?
How to test custom action filter in ASP.NET Core?
我在我的 ASP.NET 核心应用程序中创建了一个简单的操作过滤器,这个操作过滤器应该记录用户的 activity:
public class AuditAttribute : IResultFilter
{
private readonly IAuditService _audit;
private readonly IUnitOfWork _uow;
public AuditAttribute(IAuditService audit, IUnitOfWork uow)
{
_audit = audit;
_uow = uow;
}
public void OnResultExecuting(ResultExecutingContext context)
{
ar model = new Audit
{
UserName = context.HttpContext.User,
//...
};
_audit.Add(model);
_uow.SaveChanges();
}
public void OnResultExecuted(ResultExecutedContext context)
{
}
}
现在我只想知道如何为它编写单元测试。我正在使用 xUnit
和 Mock
根据您的代码,要进行单元测试,您还需要模拟 HttpContext。
顺便说一句,这一点似乎不对:UserName = context.HttpContext.User
我想你的意思是 UserName = context.HttpContext.User.Identity.Name
。不管怎样,你的测试方法应该是这样的:
public void OnResultExecuting_Test()
{
// Arrange sesction :
var httpContextWrapper = new Moq<HttpContextBase>();
var genericIdentity = new GenericIdentity("FakeUser","AuthType");
var genericPrincipal = new GenericPrincipal(genericIdentity , new string[]{"FakeRole"});
httpContextWrapper.Setup(o=> o.User).Return(genericPrincipal);
var controller = new FakeController(); // you can define a fake controller class in your test class (should inherit from MVC Controller class)
controller.controllerContext = new ControllerContext( httpContextWrapper.Object, new RouteData(), controller );
var audit = new Moq<IUnitOfWork>();
var uow = new Moq<IAuditService>();
// more code here to do assertion on audit
uow.Setup(o=>o.SaveChanges()).Verifiable();
var attribute= new AuditAttribute(audit.Object,uow.Object);
// Act Section:
attribute.OnActionExecuting( filterContext );
// Assert Section:
... // some assertions
uow.Verify();
}
我能够做到这一点的唯一方法是创建基本的具体 类 并测试 HTTPContext 结果以实现我想要实现的目标。由于我使用的是混凝土 类,因此不需要 Mock
设置:
[SetUp]
public void SetUp()
{
_actionContext = new ActionContext()
{
HttpContext = new DefaultHttpContext(),
RouteData = new RouteData(),
ActionDescriptor = new ActionDescriptor()
};
}
测试:
[Test]
public void Should_deny_request()
{
// Given
var resourceExecutingContext = new ResourceExecutingContext(_actionContext, new List<IFilterMetadata>(), new List<IValueProviderFactory>());
var attribute = new YourAttribute();
// When
attribute.OnResourceExecuting(resourceExecutingContext);
var result = (ContentResult) resourceExecutingContext.Result;
// Then
Assert.IsTrue(Equals("403", result.StatusCode.ToString()));
}
这对我有用。
我在我的 ASP.NET 核心应用程序中创建了一个简单的操作过滤器,这个操作过滤器应该记录用户的 activity:
public class AuditAttribute : IResultFilter
{
private readonly IAuditService _audit;
private readonly IUnitOfWork _uow;
public AuditAttribute(IAuditService audit, IUnitOfWork uow)
{
_audit = audit;
_uow = uow;
}
public void OnResultExecuting(ResultExecutingContext context)
{
ar model = new Audit
{
UserName = context.HttpContext.User,
//...
};
_audit.Add(model);
_uow.SaveChanges();
}
public void OnResultExecuted(ResultExecutedContext context)
{
}
}
现在我只想知道如何为它编写单元测试。我正在使用 xUnit
和 Mock
根据您的代码,要进行单元测试,您还需要模拟 HttpContext。
顺便说一句,这一点似乎不对:UserName = context.HttpContext.User
我想你的意思是 UserName = context.HttpContext.User.Identity.Name
。不管怎样,你的测试方法应该是这样的:
public void OnResultExecuting_Test()
{
// Arrange sesction :
var httpContextWrapper = new Moq<HttpContextBase>();
var genericIdentity = new GenericIdentity("FakeUser","AuthType");
var genericPrincipal = new GenericPrincipal(genericIdentity , new string[]{"FakeRole"});
httpContextWrapper.Setup(o=> o.User).Return(genericPrincipal);
var controller = new FakeController(); // you can define a fake controller class in your test class (should inherit from MVC Controller class)
controller.controllerContext = new ControllerContext( httpContextWrapper.Object, new RouteData(), controller );
var audit = new Moq<IUnitOfWork>();
var uow = new Moq<IAuditService>();
// more code here to do assertion on audit
uow.Setup(o=>o.SaveChanges()).Verifiable();
var attribute= new AuditAttribute(audit.Object,uow.Object);
// Act Section:
attribute.OnActionExecuting( filterContext );
// Assert Section:
... // some assertions
uow.Verify();
}
我能够做到这一点的唯一方法是创建基本的具体 类 并测试 HTTPContext 结果以实现我想要实现的目标。由于我使用的是混凝土 类,因此不需要 Mock
设置:
[SetUp]
public void SetUp()
{
_actionContext = new ActionContext()
{
HttpContext = new DefaultHttpContext(),
RouteData = new RouteData(),
ActionDescriptor = new ActionDescriptor()
};
}
测试:
[Test]
public void Should_deny_request()
{
// Given
var resourceExecutingContext = new ResourceExecutingContext(_actionContext, new List<IFilterMetadata>(), new List<IValueProviderFactory>());
var attribute = new YourAttribute();
// When
attribute.OnResourceExecuting(resourceExecutingContext);
var result = (ContentResult) resourceExecutingContext.Result;
// Then
Assert.IsTrue(Equals("403", result.StatusCode.ToString()));
}
这对我有用。