【问题标题】:How to mock ExceptionContext for testing using .NET Core 3 Web API and Moq如何模拟 ExceptionContext 以使用 .NET Core 3 Web API 和 Moq 进行测试
【发布时间】:2020-03-31 19:29:41
【问题描述】:

为了在 .NET Core 3 中正确测试自定义 ExceptionFilterAttribute,我们需要使用 Moq 在 Xunit 测试中模拟 ExceptionContext。我该怎么做?

异常过滤器:

public class CustomExceptionFilter : ExceptionFilterAttribute
{
  public override OnException(ExceptionContext context)
  {
    /* Code here that handles exceptions */
  }
}

我到处寻找,无法找到一种模拟这些东西的好方法,以确保没有由于其他缺失的依赖项而引发异常。如何轻松模拟ExceptionContext

【问题讨论】:

    标签: c# unit-testing .net-core moq xunit


    【解决方案1】:

    问题在于,如果您试图模拟 ExceptionContext 以返回不同的异常类型,您实际上是想模拟一个异常,然后在实例化 ExceptionContext 时使用该模拟异常。

    首先,要在测试中为过滤器实例化ExceptionContext,您需要能够实例化ActionContextActionContext 与我们的测试无关,但依赖关系树需要它,因此我们必须尽可能少地自定义实例化它:

    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
    };
    

    这样做可以让您在给定不同的异常类型时充分测试异常过滤器的行为。

    完整代码:

    [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.");
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-04
      • 1970-01-01
      • 2019-12-25
      • 1970-01-01
      • 1970-01-01
      • 2016-12-25
      • 2023-03-29
      • 1970-01-01
      相关资源
      最近更新 更多