带有ExceptionFilterAttribute的UnitTest ApiController

时间:2015-07-17 15:15:43

标签: c# unit-testing exception-handling moq asp.net-web-api2

我尝试使用UnitTest我的控制器,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
  }
}

ExceptionFilter

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

我错过了什么吗? 感谢。

1 个答案:

答案 0 :(得分:3)

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

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

[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. 创建一个UT,用于验证方法是否具有ExceptionFilters属性
  3. 例如:

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

    优点: 它很快,不容易打破,它不会使用昂贵的替代品。

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