Модульное тестирование ActionFilter - правильная настройка ActionExecutingContext - PullRequest
4 голосов
/ 03 марта 2010

В пользовательском 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 и, наоборот, метод действия с SomeAttribute этого не делает. Все идет нормально.

Теперь я хотел бы настроить некоторые модульные тесты для ActionFilter, но как я могу настроить метод действия, при котором метод OnActionExecuting должен выполняться в модульном тесте? Использование следующего кода не находит SomeAttribute в методе действия, который будет выполнен. Тест настроен правильно? Не правильно ли я что-то устроил в тесте? Чтобы уточнить, тест не завершен, но я не уверен, что я пропустил, так что someAttribute в OnActionExecuting в тесте составляет 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();
        }
    }

1 Ответ

6 голосов
/ 03 марта 2010

Поскольку свойство ActionDescriptor ActionExecutingContext является виртуальным, вы можете просто override это и предоставить собственную реализацию 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
}
...