web-dev-qa-db-ja.com

MoqでActionExecutingContextをモックする方法は?

次のフィルターをテストしようとしています。

_using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Filters;

namespace Hello
{
    public class ValidationFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (!filterContext.ModelState.IsValid) {
                filterContext.Result = new BadRequestObjectResult(filterContext.ModelState);
            }
        }
    }
}
_

Moqを使用してActionFilterAttributeをモックしようとしています。

Mvc6.0.0-rc1を使用しています

私の最初の試み:

_var context = new ActionExecutingContext(
                    new ActionContext(Mock.Of<HttpContext>(), new RouteData(), new ActionDescriptor()),
                    new IFilterMetadata[] { filter, },
                    new Dictionary<string, object>(),
                    controller: new object());
_

しかし、ModelStateをオーバーライドすることはできませんでした。読み取り専用のようです: https://github.com/aspnet/Mvc/blob/6.0.0-rc1/src/Microsoft.AspNet.Mvc.Abstractions/ActionContext.cs#L25

それから私は試しました:

_var contextMock = new Mock<ActionExecutingContext>(
                    new ActionContext(Mock.Of<HttpContext>(), new RouteData(), new ActionDescriptor()),
                    new IFilterMetadata[] { filter, },
                    new Dictionary<string, object>());
_

しかし、filter.OnActionExecuting(contextMock.Object)を呼び出すと、次のエラーが発生します。

_Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: Microsoft.AspNet.Mvc.Filters.ActionExecutingContext.
      Could not find a constructor that would match given arguments:
      Microsoft.AspNet.Mvc.ActionContext
      Microsoft.AspNet.Mvc.Filters.IFilterMetadata[]
      System.Collections.Generic.Dictionary`2[System.String,System.Object]
_

ModelStateを使用するフィルターをテストする方法は?

15
yokomizor

私は同じ問題に遭遇し、この方法でそれを解決しました。

[Fact]
public void ValidateModelAttributes_SetsResultToBadRequest_IfModelIsInvalid()
{
    var validationFilter = new ValidationFilter();
    var modelState = new ModelStateDictionary();
    modelState.AddModelError("name", "invalid");

    var actionContext = new ActionContext(
        Mock.Of<HttpContext>(),
        Mock.Of<RouteData>(),
        Mock.Of<ActionDescriptor>(),
        modelState
    );

    var actionExecutingContext = new ActionExecutingContext(
        actionContext,
        new List<IFilterMetadata>(),
        new Dictionary<string, object>(),
        Mock.Of<Controller>()
    );

    validatationFilter.OnActionExecuting(actionExecutingContext);

    Assert.IsType<BadRequestObjectResult>(actionExecutingContext.Result);
}
25
ChristofferH

IAsyncActionFilterから継承するときに、これを行う方法を誰かが疑問に思っていた場合

[Fact]
public async Task MyTest()
{
    var modelState = new ModelStateDictionary();

    var httpContextMock = new DefaultHttpContext();

    httpContextMock.Request.Query = new QueryCollection(new Dictionary<string, StringValues> {}); // if you are reading any properties from the query parameters

    var actionContext = new ActionContext(
        httpContextMock,
        Mock.Of<RouteData>(),
        Mock.Of<ActionDescriptor>(),
        modelState
    );

    var actionExecutingContext = new ActionExecutingContext(
        actionContext,
        new List<IFilterMetadata>(),
        new Dictionary<string, object>(),
        Mock.Of<Controller>()
    )
    {
        Result = new OkResult() // It will return ok unless during code execution you change this when by condition
    };

    Mymock1.SetupGet(x => x.SomeProperty).Returns("MySomething");
    Mymock2.Setup(x => x.GetSomething(It.IsAny<string>(), It.IsAny<string>())).ReturnsAsync(true);

    var context = new ActionExecutedContext(actionContext, new List<IFilterMetadata>(), Mock.Of<Controller>());

    await _classUnderTest.OnActionExecutionAsync(actionExecutingContext, async () => { return context; });

    actionExecutingContext.Result.Should().BeOfType<OkResult>();
}
2
vsarunov