对 ActionFilter 进行单元测试 - 正确设置 ActionExecutingContext

发布于 2024-08-23 17:18:15 字数 2414 浏览 5 评论 0原文

在自定义 ActionFilter 中,我想检查将执行的控制器操作的属性。通过一个小型测试应用程序运行,在 asp.net 开发服务器中启动应用程序时,以下工作正常 -

public class CustomActionFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var someAttribute = filterContext.ActionDescriptor
                                    .GetCustomAttributes(typeof(SomeAttribute), false)
                                    .Cast<SomeAttribute>()
                                    .SingleOrDefault();

        if (someAttribute == null)
        {
            throw new ArgumentException();
        }

        // do something here
    }

    public override void OnActionExecuted(ActionExecutingContext filterContext)
    {
        // ...
    }
}

没有 SomeAttribute 的操作方法会抛出 ArgumentException ,反之,操作方法会抛出 ArgumentExceptionSomeAttribute 则不然。到目前为止,一切都很好。

现在我想为 ActionFilter 设置一些单元测试,但是如何设置 OnActionExecuting 方法应在单元测试中运行的操作方法?使用以下代码在将要执行的操作方法上找不到 SomeAttribute 。测试设置是否正确?我在测试中没有安排正确的事情吗?澄清一下,测试尚未完成,但我不确定我错过了什么,导致测试中 OnActionExecuting 中的 someAttributenull

    [TestMethod]
    public void Controller_With_SomeAttribute()
    {
        FakeController fakeController =
            new FakeController();

        ControllerContext controllerContext = 
            new ControllerContext(new Mock<HttpContextBase>().Object, 
                                  new RouteData(), 
                                  fakeController);

        var actionDescriptor = new Mock<ActionDescriptor>();
        actionDescriptor.SetupGet(x => x.ActionName).Returns("Action_With_SomeAttribute");

        ActionExecutingContext actionExecutingContext =
            new ActionExecutingContext(controllerContext,
                                       actionDescriptor.Object, 
                                       new RouteValueDictionary());

        CustomActionFilterAttribute customActionFilterAttribute = new CustomActionFilterAttribute ();
        customActionFilterAttribute.OnActionExecuting(actionExecutingContext);
    }

    private class FakeController : Controller
    {
        [SomeAttribute]
        ActionResult Action_With_SomeAttribute()
        {
            return View();
        }
    }

In a custom ActionFilter, I want check the attributes on the controller action that will be executed. Running through a small test application, the following works when launching the app in the asp.net development server-

public class CustomActionFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var someAttribute = filterContext.ActionDescriptor
                                    .GetCustomAttributes(typeof(SomeAttribute), false)
                                    .Cast<SomeAttribute>()
                                    .SingleOrDefault();

        if (someAttribute == null)
        {
            throw new ArgumentException();
        }

        // do something here
    }

    public override void OnActionExecuted(ActionExecutingContext filterContext)
    {
        // ...
    }
}

An action method without SomeAttribute throws an ArgumentException and conversely, an action method with SomeAttribute does not. So far so good.

Now I would like to set up some unit tests for the ActionFilter, but how can I set up the action method upon which the OnActionExecuting method should run in the unit test? Using the following code doesn't find SomeAttribute on the action method which will be executed. Is the test set up correctly? Have I not arranged something correctly in the test? To clarify, the test is not complete but I'm not sure what I've missed such that someAttribute in OnActionExecuting in the test is null

    [TestMethod]
    public void Controller_With_SomeAttribute()
    {
        FakeController fakeController =
            new FakeController();

        ControllerContext controllerContext = 
            new ControllerContext(new Mock<HttpContextBase>().Object, 
                                  new RouteData(), 
                                  fakeController);

        var actionDescriptor = new Mock<ActionDescriptor>();
        actionDescriptor.SetupGet(x => x.ActionName).Returns("Action_With_SomeAttribute");

        ActionExecutingContext actionExecutingContext =
            new ActionExecutingContext(controllerContext,
                                       actionDescriptor.Object, 
                                       new RouteValueDictionary());

        CustomActionFilterAttribute customActionFilterAttribute = new CustomActionFilterAttribute ();
        customActionFilterAttribute.OnActionExecuting(actionExecutingContext);
    }

    private class FakeController : Controller
    {
        [SomeAttribute]
        ActionResult Action_With_SomeAttribute()
        {
            return View();
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

じ违心 2024-08-30 17:18:15

由于 ActionExecutingContext 的 ActionDescriptor 属性是虚拟的,因此您可以覆盖它并提供您自己的 ActionDescriptor 实现。

以下是通过 OnActionExecuting 当前实现验证两个分支的两个测试:

[ExpectedException(typeof(ArgumentException))]
[TestMethod]
public void OnActionExecutingWillThrowWhenSomeAttributeIsNotPresent()
{
    // Fixture setup
    var ctxStub = new Mock<ActionExecutingContext>();
    ctxStub.Setup(ctx => ctx.ActionDescriptor.GetCustomAttributes(typeof(SomeAttribute), false))
        .Returns(new object[0]);

    var sut = new CustomActionFilterAttribute();
    // Exercise system
    sut.OnActionExecuting(ctxStub.Object);
    // Verify outcome (expected exception)
    // Teardown
}

[TestMethod]
public void OnActionExecutingWillNotThrowWhenSomeAttributeIsPresent()
{
    // Fixture setup
    var ctxStub = new Mock<ActionExecutingContext>();
    ctxStub.Setup(ctx => ctx.ActionDescriptor.GetCustomAttributes(typeof(SomeAttribute), false))
        .Returns(new object[] { new SomeAttribute() });

    var sut = new CustomActionFilterAttribute();
    // Exercise system
    sut.OnActionExecuting(ctxStub.Object);
    // Verify outcome (no exception indicates success)
    // Teardown
}

Since the ActionDescriptor property of ActionExecutingContext is virtual, you can just override that and provide your own implementation of ActionDescriptor.

Here are two tests that verify the two branches through the current implementation of OnActionExecuting:

[ExpectedException(typeof(ArgumentException))]
[TestMethod]
public void OnActionExecutingWillThrowWhenSomeAttributeIsNotPresent()
{
    // Fixture setup
    var ctxStub = new Mock<ActionExecutingContext>();
    ctxStub.Setup(ctx => ctx.ActionDescriptor.GetCustomAttributes(typeof(SomeAttribute), false))
        .Returns(new object[0]);

    var sut = new CustomActionFilterAttribute();
    // Exercise system
    sut.OnActionExecuting(ctxStub.Object);
    // Verify outcome (expected exception)
    // Teardown
}

[TestMethod]
public void OnActionExecutingWillNotThrowWhenSomeAttributeIsPresent()
{
    // Fixture setup
    var ctxStub = new Mock<ActionExecutingContext>();
    ctxStub.Setup(ctx => ctx.ActionDescriptor.GetCustomAttributes(typeof(SomeAttribute), false))
        .Returns(new object[] { new SomeAttribute() });

    var sut = new CustomActionFilterAttribute();
    // Exercise system
    sut.OnActionExecuting(ctxStub.Object);
    // Verify outcome (no exception indicates success)
    // Teardown
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文