【问题标题】:UnitTest ApiController with ExceptionFilterAttribute带有 ExceptionFilterAttribute 的 UnitTest ApiController
【发布时间】:2015-07-17 15:15:43
【问题描述】:

我正在尝试对我的控制器进行单元测试,其中异常被 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

我错过了什么吗? 谢谢。

【问题讨论】:

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


    【解决方案1】:

    您的测试直接针对控制器。 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 属性

    例如:

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

    优点: 它很快,不容易破解,不使用昂贵的资源。

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

    【讨论】:

    • 谢谢!它真的帮助了我。对于这些测试的重量,这并不重要。它们将是仅在 Deploy 上启动的组件测试方法,所以它会很好!再次感谢伙计!
    猜你喜欢
    • 1970-01-01
    • 2015-05-03
    • 1970-01-01
    • 1970-01-01
    • 2015-10-16
    • 1970-01-01
    • 2019-11-06
    • 2023-03-18
    • 1970-01-01
    相关资源
    最近更新 更多