带有 ExceptionFilterAttribute 的 UnitTest ApiController

UnitTest ApiController with ExceptionFilterAttribute

我正在尝试对我的控制器进行单元测试,其中异常被 ExceptionFilterAttribute 捕获并作为 HttpResponseException 启动。

控制器

[ExceptionFilters] //ExceptionFilterAttribute
public class EleveController : ApiController
{ 
  private IGpiRepository _gpiRepository;

  public EleveController(IGpiRepository gpiRepository)
  {
     _gpiRepository = gpiRepository;
  }

  [HttpGet]
  [Route("{fiche:int}/grouperepere")]
  public GroupeRepere GroupeRepere(int fiche) //This What Im trying to test
  {
     GpiService service = new GpiService(_gpiRepository);
     return service.Get(fiche); //Throw an ArgumentNullException when fiche == 0
  }
}

异常过滤器

public class ExceptionFilters : ExceptionFilterAttribute
{
  public override void OnException(HttpActionExecutedContext context)
  {
     if (context.Exception is NotImplementedException)
     {
        context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
     }
     else if (context.Exception is ArgumentNullException)
     {
        context.Response = new HttpResponseMessage(HttpStatusCode.BadRequest)
        {
           Content = new StringContent(string.Format("Argument \"{0}\" is null or invalid", ((ArgumentNullException)context.Exception).ParamName)),
           ReasonPhrase = "Argument null or invalid"
        };
     }
  }

这是我的测试:

  private IGpiRepository _gpiRepository;
  private Mock<ICallApi> _callApi;
  private EleveController _controller;

  [TestInitialize]
  public void Initialize()
  {
     _callApi = new Mock<ICallApi>();
     _gpiRepository = new GpiRepository(_callApi.Object);
     _controller = new EleveController(_gpiRepository);
  }

  [TestMethod]
  public void EleveController__GroupeRepere_WithBadFiche_400BadRequest()
  {
     string noGroupe = "111";
     int fiche = 0;
     try
     {
        GroupeRepere gp = _controller.GroupeRepere(fiche);

        Assert.Fail();
     }
     catch (Exception e)
     {
        Assert.IsTrue(e is HttpResponseException); // not working --> ArgumentNullException
     }
  }

问题是 e 仍然是 ArgumentNullException。当我继续调试时,它甚至没有达到 ExceptionFilter class

我错过了什么吗? 谢谢。

您的测试直接针对控制器。 ExceptionFilterAttribute 取决于服务器。(记住:属性是 Metadata

测试行为的方法是使用 IIS 服务器或 SelfHost Server,然后在您的测试中提升服务器 class 并发送请求:

[TestInitialize]
public void Initialize()
{
    _callApi = new Mock<ICallApi>();
    _gpiRepository = new GpiRepository(_callApi.Object);

   //initialize your server
   //set _gpiRepository as a dependency and etc..
}
[TestMethod]
public void EleveController__GroupeRepere_WithBadFiche_400BadRequest()
{
    //configure the request
    var result = client.ExecuteAsGet<GroupeRepere>(<your request>);

    Assert.AreEqual(HttpStatusCode.BadRequest,result.StatusCode);
}

在我看来,除非你的控制器是 public Api 的一部分,否则你不应该出错代码。(原因很简单,这种测试很容易被破坏,它们很慢并且使用昂贵的资源)如果你的控制器是一部分 public Api 您应该通过 Acceptance tests 对其进行测试,然后确认没有任何内容覆盖预期的行为。

如果您仍想测试此行为 那么我想为您提供另一种测试方法:

  1. 针对 ExceptionFilters 创建 UT。
  2. 创建一个验证该方法具有 ExceptionFilters 属性的 UT

例如:

[TestMethod]
public void GroupeRepere_HasExceptionFiltersAttribute()
 {
    var attribute = typeof (UnitTest2).GetMethod("GroupeRepere").GetCustomAttributes(true);

    foreach (var att in attribute)
    {
        if(att.GetType() is typeof(ExceptionFilters))
        {
            return;
        }
    }
    Assert.Fail();
}

优点: 它速度快,不易损坏,不使用昂贵的资源。

缺点: 在生产中,某些设置可能会覆盖预期的行为。