我如何为这个 actionfilter 编写单元测试
How can i write unit test for this actionfilter
public MyContext _db;
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (_db == null || !_db.ChangeTracker.HasChanges())
{
return;
}
try
{
_db.SaveChanges();
}
catch
{
}
}
这是我的 wep api 项目的动作过滤器。 _db 上下文对象按请求注入此过滤器。我的意思是在服务层完成所有处理后调用一次 SaveChanges() 方法。我的问题是如何测试这个过滤器?我如何模拟在任何控制器或服务层中可能发生的异常情况,以及当异常抛出 saveChanges() 从未调用过的情况?如何设置应用程序中任何地方发生异常的情况?
如果在执行请求时发生 未处理 异常,则 actionExecutedContext
上的 Exception
属性 将包含该异常。这是框架的一部分,而不是你需要测试的东西。在您的测试中,您可以简单地手动设置 Exception
属性 并断言该属性采取正确的操作。
[Fact]
public void Saves_data_on_failure()
{
var mockDbContext = new Mock<IDbContext>();
var myAttribute = new MyAttribute(mockDbContext.Object);
var executionContext = new HttpActionExecutedContext
{
Exception = new Exception("Request failed.")
};
myAttribute.OnActionExecuted(executionContext);
mockDbContext.Verify(d => d.SaveChanges());
}
您可能还需要考虑是否要为所有类型的异常保存数据。数据可能处于 invalid/unknown 状态。
上周,我一直在为我的 WebAPI 2 操作过滤器做同样的事情。
我有一个验证我的 ModelState 的操作过滤器,如果出现任何错误,它会抛出一个包含 200 个 HTTPcode 的错误列表。
操作看起来像这样:
public class ModelValidationActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var modelState = actionContext.ModelState;
if (!modelState.IsValid)
{
actionContext.Response = ...
}
}
}
单元测试
var httpControllerContext = new HttpControllerContext
{
Request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/someUri")
{
Content = new ObjectContent(typeof(MyModel),
new MyModel(), new JsonMediaTypeFormatter())
},
RequestContext = new HttpRequestContext()
};
httpControllerContext.Request = new HttpRequestMessage();
httpControllerContext.Request.SetConfiguration(new HttpConfiguration());
var httpActionContext = new HttpActionContext { ControllerContext = httpControllerContext };
var filter = new ModelValidationActionFilterAttribute();
httpActionContext.ModelState.AddModelError("*", "Invalid model state");
// act
filter.OnActionExecuting(httpActionContext);
// assert
httpActionContext.Response.ShouldNotBe(null);
httpActionContext.Response.ShouldBeOfType(typeof (HttpResponseMessage));
var result = httpActionContext.Response.Content.ReadAsStringAsync().Result;
BaseServiceResponse<object> resultResponse =
JsonConvert.DeserializeObject<BaseServiceResponse<object>>(result);
resultResponse.Data.ShouldBe(null);
resultResponse.Messages.Count.ShouldBe(1);
resultResponse.Messages.First().Description.ShouldBe("Invalid model state");
在您的情况下,您需要使用 IDbContext 接口模拟数据库上下文 - 请参阅此处:http://aikmeng.com/post/62817541825/how-to-mock-dbcontext-and-dbset-with-moq-for-unit
public MyContext _db;
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (_db == null || !_db.ChangeTracker.HasChanges())
{
return;
}
try
{
_db.SaveChanges();
}
catch
{
}
}
这是我的 wep api 项目的动作过滤器。 _db 上下文对象按请求注入此过滤器。我的意思是在服务层完成所有处理后调用一次 SaveChanges() 方法。我的问题是如何测试这个过滤器?我如何模拟在任何控制器或服务层中可能发生的异常情况,以及当异常抛出 saveChanges() 从未调用过的情况?如何设置应用程序中任何地方发生异常的情况?
如果在执行请求时发生 未处理 异常,则 actionExecutedContext
上的 Exception
属性 将包含该异常。这是框架的一部分,而不是你需要测试的东西。在您的测试中,您可以简单地手动设置 Exception
属性 并断言该属性采取正确的操作。
[Fact]
public void Saves_data_on_failure()
{
var mockDbContext = new Mock<IDbContext>();
var myAttribute = new MyAttribute(mockDbContext.Object);
var executionContext = new HttpActionExecutedContext
{
Exception = new Exception("Request failed.")
};
myAttribute.OnActionExecuted(executionContext);
mockDbContext.Verify(d => d.SaveChanges());
}
您可能还需要考虑是否要为所有类型的异常保存数据。数据可能处于 invalid/unknown 状态。
上周,我一直在为我的 WebAPI 2 操作过滤器做同样的事情。
我有一个验证我的 ModelState 的操作过滤器,如果出现任何错误,它会抛出一个包含 200 个 HTTPcode 的错误列表。
操作看起来像这样:
public class ModelValidationActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var modelState = actionContext.ModelState;
if (!modelState.IsValid)
{
actionContext.Response = ...
}
}
}
单元测试
var httpControllerContext = new HttpControllerContext
{
Request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/someUri")
{
Content = new ObjectContent(typeof(MyModel),
new MyModel(), new JsonMediaTypeFormatter())
},
RequestContext = new HttpRequestContext()
};
httpControllerContext.Request = new HttpRequestMessage();
httpControllerContext.Request.SetConfiguration(new HttpConfiguration());
var httpActionContext = new HttpActionContext { ControllerContext = httpControllerContext };
var filter = new ModelValidationActionFilterAttribute();
httpActionContext.ModelState.AddModelError("*", "Invalid model state");
// act
filter.OnActionExecuting(httpActionContext);
// assert
httpActionContext.Response.ShouldNotBe(null);
httpActionContext.Response.ShouldBeOfType(typeof (HttpResponseMessage));
var result = httpActionContext.Response.Content.ReadAsStringAsync().Result;
BaseServiceResponse<object> resultResponse =
JsonConvert.DeserializeObject<BaseServiceResponse<object>>(result);
resultResponse.Data.ShouldBe(null);
resultResponse.Messages.Count.ShouldBe(1);
resultResponse.Messages.First().Description.ShouldBe("Invalid model state");
在您的情况下,您需要使用 IDbContext 接口模拟数据库上下文 - 请参阅此处:http://aikmeng.com/post/62817541825/how-to-mock-dbcontext-and-dbset-with-moq-for-unit