C# 如何模拟ExceptionContext以使用.NET Core 3 Web API和Moq进行测试
为了正确测试.NET Core 3中的自定义ExceptionFilterAttribute,我们需要使用Moq在Xunit测试中模拟ExceptionContext。我该怎么做 异常筛选器:C# 如何模拟ExceptionContext以使用.NET Core 3 Web API和Moq进行测试,c#,unit-testing,.net-core,moq,xunit,C#,Unit Testing,.net Core,Moq,Xunit,为了正确测试.NET Core 3中的自定义ExceptionFilterAttribute,我们需要使用Moq在Xunit测试中模拟ExceptionContext。我该怎么做 异常筛选器: public class CustomExceptionFilter : ExceptionFilterAttribute { public override OnException(ExceptionContext context) { /* Code here that handles
public class CustomExceptionFilter : ExceptionFilterAttribute
{
public override OnException(ExceptionContext context)
{
/* Code here that handles exceptions */
}
}
我到处都找过了,找不到一个好方法来模拟这些东西,以确保不会因为其他缺少的依赖项而引发异常。如何轻松模拟
ExceptionContext
?问题在于,如果您试图模拟ExceptionContext
以返回不同的异常类型,实际上您希望模拟一个异常,然后在实例化ExceptionContext
时使用该模拟异常
首先,要在测试中为过滤器实例化ExceptionContext
,您需要能够实例化ActionContext
。ActionContext
与我们的测试无关,但依赖关系树需要它,因此我们必须尽可能少地定制它:
var actionContext = new ActionContext()
{
HttpContext = new DefaultHttpContext(),
RouteData = new RouteData(),
ActionDescriptor = new ActionDescriptor()
};
在能够实例化ActionContext
之后,可以实例化ExceptionContext。这里我们还模拟了用于构建ExceptionContext
的异常。这是最重要的一步,因为这是改变我们正在测试的行为的值
// The stacktrace message and source member variables are virtual and so we can stub them here.
var mockException = new Mock<Exception>();
mockException.Setup(e => e.StackTrace)
.Returns("Test stacktrace");
mockException.Setup(e => e.Message)
.Returns("Test message");
mockException.Setup(e => e.Source)
.Returns("Test source");
var exceptionContext = new ExceptionContext(actionContext, new List<FilterMetadata>())
{
Exception = mockException.Object
};
//stacktrace消息和源成员变量是虚拟的,因此我们可以在这里存根它们。
var mockException=new Mock();
mockException.Setup(e=>e.StackTrace)
.返回(“测试跟踪”);
mockException.Setup(e=>e.Message)
.返回(“测试消息”);
mockException.Setup(e=>e.Source)
.返回(“测试源”);
var exceptionContext=new exceptionContext(actionContext,new List())
{
Exception=mockException.Object
};
这样做允许您在给定不同的异常类型时充分测试异常过滤器的行为
完整代码:
[Fact]
public void TestExceptionFilter()
{
var actionContext = new ActionContext()
{
HttpContext = new DefaultHttpContext(),
RouteData = new RouteData(),
ActionDescriptor = new ActionDescriptor()
};
// The stacktrace message and source member variables are virtual and so we can stub them here.
var mockException = new Mock<Exception>();
mockException.Setup(e => e.StackTrace)
.Returns("Test stacktrace");
mockException.Setup(e => e.Message)
.Returns("Test message");
mockException.Setup(e => e.Source)
.Returns("Test source");
// the List<FilterMetadata> here doesn't have much relevance in the test but is required
// for instantiation. So we instantiate a new instance of it with no members to ensure
// it does not effect the test.
var exceptionContext = new ExceptionContext(actionContext, new List<FilterMetadata>())
{
Exception = mockException.Object
};
var filter = new CustomExceptionFilter();
filter.OnException(exceptionContext);
// Assumption here that your exception filter modifies status codes.
// Just used as an example of how you can assert in this test.
context.HttpContext.Response.StatusCode.Should().Be(500,
"Because the response code should match the exception thrown.");
}
[事实]
public void TestExceptionFilter()
{
var actionContext=new actionContext()
{
HttpContext=新的DefaultHttpContext(),
RoutedData=新RoutedData(),
ActionDescriptor=新的ActionDescriptor()
};
//stacktrace消息和源成员变量是虚拟的,因此我们可以在这里存根它们。
var mockException=new Mock();
mockException.Setup(e=>e.StackTrace)
.返回(“测试跟踪”);
mockException.Setup(e=>e.Message)
.返回(“测试消息”);
mockException.Setup(e=>e.Source)
.返回(“测试源”);
//这里的列表在测试中没有太大的相关性,但是是必需的
//所以我们实例化了一个新的实例,没有需要确保的成员
//它不会影响测试。
var exceptionContext=new exceptionContext(actionContext,new List())
{
Exception=mockException.Object
};
var filter=new CustomExceptionFilter();
filter.OnException(exceptionContext);
//这里假设您的异常过滤器修改状态代码。
//这只是一个示例,说明如何在这个测试中断言。
context.HttpContext.Response.StatusCode.Should()应为(500,
“因为响应代码应该与引发的异常匹配。”);
}