【问题标题】:How to mock ActionExecutingContext with Moq?如何用 Moq 模拟 ActionExecutingContext?
【发布时间】:2016-08-06 09:05:02
【问题描述】:

我正在尝试测试以下过滤器:

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。

我正在使用 Mvc 6.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 的过滤器?

【问题讨论】:

    标签: asp.net-mvc unit-testing moq xunit


    【解决方案1】:

    我只是偶然发现了同样的问题并以这种方式解决了它。

    [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>()
        );
    
        validationFilter.OnActionExecuting(actionExecutingContext);
    
        Assert.IsType<BadRequestObjectResult>(actionExecutingContext.Result);
    }
    

    【讨论】:

    • 一些用法:using System;使用 System.Net;使用 Microsoft.AspNetCore.Mvc;使用 Microsoft.AspNetCore.Mvc.Filters;
    【解决方案2】:

    如果有人想知道当您从 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>();
    }
    

    【讨论】:

      猜你喜欢
      • 2019-10-06
      • 1970-01-01
      • 1970-01-01
      • 2012-03-18
      • 2010-10-19
      • 2016-09-30
      • 1970-01-01
      • 2020-10-27
      • 2012-06-01
      相关资源
      最近更新 更多