【发布时间】:2012-08-04 14:18:27
【问题描述】:
我希望在我的服务中添加一个操作过滤器,以处理将链接数据添加到响应消息中。我发现我需要模拟 HttpActionExecutedContext 但它是一个难以模拟的类,你如何处理动作过滤器测试?
【问题讨论】:
标签: .net unit-testing asp.net-web-api action-filter
我希望在我的服务中添加一个操作过滤器,以处理将链接数据添加到响应消息中。我发现我需要模拟 HttpActionExecutedContext 但它是一个难以模拟的类,你如何处理动作过滤器测试?
【问题讨论】:
标签: .net unit-testing asp.net-web-api action-filter
引用https://stackoverflow.com/a/44447349/5547177
您可以使用以下内容自己创建一个 HTTPActionContext:
_ctx = new HttpActionContext
{
ControllerContext = new HttpControllerContext()
{
Request = new HttpRequestMessage()
}
};
_ctx.Request.Properties[System.Web.Http.Hosting.HttpPropertyKeys.HttpConfigurationKey] = new HttpConfiguration();
诀窍是没有Request.Properties入口设置,它会显示错误:
请求没有关联的配置对象或 提供的配置为空。
这可能是设计者的疏忽,因为您可以在 HTTPActionContext 构造函数中设置 HTTPConfiguration!
【讨论】:
这是 2018 年的一个工作示例(.NET Framework 4.5.1)。它使用 ExceptionFilterAttribute,但对于其他 FilterAttributes 应该是类似的。
[Test]
public void MyTest()
{
var request = new HttpRequestMessage(HttpMethod.Get, new Uri("http://www.google.com"));
var response = new HttpResponseMessage();
// This next line is necessary to avoid the following error
// if you call `context.Request.CreateResponse(...)` inside the filter:
// System.InvalidOperationException: The request does not have an associated configuration object or the provided configuration was null.
// Discovered from https://stackoverflow.com/a/44447355/3312114
request.SetConfiguration(new HttpConfiguration());
var context = ContextUtil.GetActionExecutedContext(request, response);
_myFilter.OnException(context); // Execute your methods
Assert.AreEqual(HttpStatusCode.InternalServerError, context.Response.StatusCode); // Make your assertions
}
然后只需将 ContextUtil 类复制到您的测试项目中的某个位置。 @thomasb 对@tugberk 答案的评论表明最新代码是on Codeplex。虽然该评论是在 2014 年,所以甚至可能会有以后的代码,但 2014 年的代码对我有用(2018 年 1 月),而原始链接代码却没有。为方便起见,我复制了下面的更高版本。只需将其放入一个新文件中即可。
internal static class ContextUtil
{
public static HttpControllerContext CreateControllerContext(HttpConfiguration configuration = null, IHttpController instance = null, IHttpRouteData routeData = null, HttpRequestMessage request = null)
{
HttpConfiguration config = configuration ?? new HttpConfiguration();
IHttpRouteData route = routeData ?? new HttpRouteData(new HttpRoute());
HttpRequestMessage req = request ?? new HttpRequestMessage();
req.SetConfiguration(config);
req.SetRouteData(route);
HttpControllerContext context = new HttpControllerContext(config, route, req);
if (instance != null)
{
context.Controller = instance;
}
context.ControllerDescriptor = CreateControllerDescriptor(config);
return context;
}
public static HttpActionContext CreateActionContext(HttpControllerContext controllerContext = null, HttpActionDescriptor actionDescriptor = null)
{
HttpControllerContext context = controllerContext ?? ContextUtil.CreateControllerContext();
HttpActionDescriptor descriptor = actionDescriptor ?? CreateActionDescriptor();
descriptor.ControllerDescriptor = context.ControllerDescriptor;
return new HttpActionContext(context, descriptor);
}
public static HttpActionContext GetHttpActionContext(HttpRequestMessage request)
{
HttpActionContext actionContext = CreateActionContext();
actionContext.ControllerContext.Request = request;
return actionContext;
}
public static HttpActionExecutedContext GetActionExecutedContext(HttpRequestMessage request, HttpResponseMessage response)
{
HttpActionContext actionContext = CreateActionContext();
actionContext.ControllerContext.Request = request;
HttpActionExecutedContext actionExecutedContext = new HttpActionExecutedContext(actionContext, null) { Response = response };
return actionExecutedContext;
}
public static HttpControllerDescriptor CreateControllerDescriptor(HttpConfiguration config = null)
{
if (config == null)
{
config = new HttpConfiguration();
}
return new HttpControllerDescriptor() { Configuration = config, ControllerName = "FooController" };
}
public static HttpActionDescriptor CreateActionDescriptor()
{
var mock = new Mock<HttpActionDescriptor>() { CallBase = true };
mock.SetupGet(d => d.ActionName).Returns("Bar");
return mock.Object;
}
}
【讨论】:
System.MissingMethodException : Method not found: 'Void System.Web.Http.Controllers.HttpControllerContext.set_Request(System.Net.Http.HttpRequestMessage)'. - 有什么想法吗?
MissingMethodException。
我也一直在用头撞砖墙。我尝试了contextUtil,但不断收到空引用异常。我发现了如何在this post 中调用 actionFilter 注:使用过滤器的 Mock 实例时未调用 actionFilter,我必须使用真实对象。 高温
具体来说:
var httpActionContext = new HttpActionContext
{
ControllerContext = new HttpControllerContext
{
Request = requestMessage
}
};
//call filter
var filter = new FooFilter();
filter.OnActionExecuting(httpActionContext);
【讨论】:
刚刚更新。
private HttpActionContext CreateExecutingContext()
{
return new HttpActionContext { ControllerContext = new HttpControllerContext { Request = new HttpRequestMessage() } };
}
private HttpActionExecutedContext CreateExecutedContextWithStatusCode(HttpStatusCode statusCode)
{
return new HttpActionExecutedContext
{
ActionContext = new HttpActionContext
{
ControllerContext = new HttpControllerContext
{
Request = new HttpRequestMessage()
}
},
Response = new HttpResponseMessage
{
StatusCode = statusCode,
Content = new StringContent("blah")
}
};
}
【讨论】:
我在尝试测试我构建的自定义未处理异常过滤器时遇到了同样的问题。
这成功了。大量的更新和很长的代码行。
var httpActionExecutedContext = new HttpActionExecutedContext(
new HttpActionContext(
new HttpControllerContext(
new HttpConfiguration(),
Substitute.For<IHttpRouteData>(),
new HttpRequestMessage()),
Substitute.For<HttpActionDescriptor>()),
null);
使用了 NSubstiute,但您选择的任何处理抽象基类的模拟框架都可以。
希望对你有帮助
【讨论】:
您可以为HttpActionExecutedContext 创建一个假的,如下所示:
public static HttpActionContext CreateActionContext(HttpControllerContext controllerContext = null, HttpActionDescriptor actionDescriptor = null)
{
HttpControllerContext context = controllerContext ?? ContextUtil.CreateControllerContext();
HttpActionDescriptor descriptor = actionDescriptor ?? new Mock<HttpActionDescriptor>() { CallBase = true }.Object;
return new HttpActionContext(context, descriptor);
}
public static HttpActionExecutedContext GetActionExecutedContext(HttpRequestMessage request, HttpResponseMessage response)
{
HttpActionContext actionContext = CreateActionContext();
actionContext.ControllerContext.Request = request;
HttpActionExecutedContext actionExecutedContext = new HttpActionExecutedContext(actionContext, null) { Response = response };
return actionExecutedContext;
}
我刚刚从 ASP.NET Web API 源代码中复制并粘贴了该代码:ContextUtil 类。以下是他们如何测试一些内置过滤器的一些示例:
ActionFilterAttributeTest 是 ActionFilterAttribute 的测试类,它是一个抽象类,但你会明白的。
【讨论】: