【问题标题】:Testing MVC Controller Action HttpAcceptAttribute Verbs测试 MVC 控制器操作 HttpAcceptAttribute 动词
【发布时间】:2010-08-29 23:05:54
【问题描述】:

对控制器操作 HttpAcceptAttribute 动词进行单元测试的最佳方法是什么?

到目前为止,我有以下,但它是如此丑陋,即使是一个母亲也不能爱它,而且不是很灵活。有没有更好的办法?

[Fact] // using xUnit, mocking controller in class
public void FilterControllerTestRemoveFilterByProductAttributeIsOfTypePost()
{
    Type[] paramTypes = new[] { typeof(int) };
    var method = typeof(FilterController).GetMethod("MyMethod", paramTypes);

    var attributes = method.GetCustomAttributes(typeof(AcceptVerbsAttribute), false).Cast<AcceptVerbsAttribute>().SingleOrDefault();
    Assert.NotNull(attributes);
    Assert.Equal(1, attributes.Verbs.Count());
    Assert.True(attributes.Verbs.First().Equals(HttpVerbs.Post.ToString(), StringComparison.InvariantCultureIgnoreCase));
}

谢谢 马克

【问题讨论】:

    标签: c# unit-testing model-view-controller xunit.net acceptverbs


    【解决方案1】:

    没有反射和魔术字符串,在不破坏单元测试的情况下轻松重命名控制器和方法:

    [TestMethod]
    public void HomeController_Index_Action_Should_Accept_Post_Verb_Only()
    {
        Expression<Action<HomeController>> expression = (HomeController c) => c.Index(null);
        var methodCall = expression.Body as MethodCallExpression;
        var acceptVerbs = (AcceptVerbsAttribute[])methodCall.Method.GetCustomAttributes(typeof(AcceptVerbsAttribute), false);
        acceptVerbs.ShouldNotBeNull("");
        acceptVerbs.Length.ShouldBe(1);
        acceptVerbs[0].Verbs.First().ShouldBe("POST");
    }
    

    【讨论】:

      【解决方案2】:
      using System;
      using System.Linq;
      using System.Reflection;
      using System.Web.Mvc;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      
      namespace Unknown.Tests
      {
      
          public static class MvcAssert
          {
      
              public static MemberInfo[] HasPostAction(Controller controller, string actionName, int expectedCount)
              {
                  if (controller == null)
                      throw new ArgumentNullException("controller");
      
                  if (string.IsNullOrEmpty(actionName))
                      throw new ArgumentNullException("actionName");
      
                  MemberInfo[] members = controller.GetType().FindMembers(
                      MemberTypes.Method,
                      BindingFlags.Public | BindingFlags.Instance,
                      (m, c) => (m.Name == actionName && m.IsDefined(typeof(AcceptVerbsAttribute), false) && ((AcceptVerbsAttribute)Attribute.GetCustomAttribute(m, typeof(AcceptVerbsAttribute))).Verbs.Any((v) => v.Equals("Post", StringComparison.InvariantCultureIgnoreCase))),
                      null);
      
                  Assert.AreEqual<int>(expectedCount, members.Length);
      
                  return members;
              }
      
          }
      
      }
      

      使用

      public void FilterControllerTestRemoveFilterByProductAttributeIsOfTypePost()
      {
          FilterController controller = new FilterController();
          MvcAssert.HasPostAction(controller, "RemoveFilterByProduct", 1);
      }
      

      【讨论】:

      • 看起来不错。谢谢 进一步完善这个想法,您是否认为有一种方法可以使其更加通用,以允许传入 HttpVerbs 数组并让方法 Assert 只有 HttpVerbs 是完全匹配的,或者是过度杀伤和单独的方法对于发布、获取、删除、放置或它们的组合是否足够?理想情况下,我希望能够将其称为 MvcAssert.HasHttpVerbs(controller, actionName, paramTypes, HttpVerbs[]);
      【解决方案3】:
      using System;
      using System.Linq;
      using System.Reflection;
      using System.Web.Mvc;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      
      namespace MvcApplication4.Tests
      {
      
          public static class MvcAssert
          {
      
              public static MethodInfo ActionExists(Controller controller, string actionName, HttpVerbs expectedVerbs, params Type[] paramTypes)
              {
                  if (controller == null)
                      throw new ArgumentNullException("controller");
      
                  if (string.IsNullOrEmpty(actionName))
                      throw new ArgumentNullException("actionName");
      
                  int actualVerbs = 0;
      
                  MethodInfo action = controller.GetType().GetMethod(actionName, paramTypes);
                  Assert.IsNotNull(action, string.Format("The specified action '{0}' could not be found.", actionName));
      
                  AcceptVerbsAttribute acceptVerb = Attribute.GetCustomAttribute(action, typeof(AcceptVerbsAttribute)) as AcceptVerbsAttribute;
      
                  if (acceptVerb == null)
                      actualVerbs = (int)HttpVerbs.Get;
                  else
                      actualVerbs = (int)Enum.Parse(typeof(HttpVerbs), string.Join(", ", acceptVerb.Verbs.ToArray()), true);
      
                  Assert.AreEqual<int>(actualVerbs, (int)expectedVerbs);
      
                  return action;
              }
      
          }
      
      }
      

      【讨论】:

        【解决方案4】:

        稍加修改的版本达林的解决方案。

          [Fact]
          public void Delete_Verb(){
            VerifyVerb<HttpDeleteAttribute>(x=>x.Delete(null));
          }
        
          protected void VerifyVerb<TVerbType>(Expression<Action<T>> exp){
              var methodCall = exp.Body as MethodCallExpression;
              var acceptVerbs = methodCall.Method
                .GetCustomAttributes(typeof(TVerbType), false);
              acceptVerbs.Should().Not.Be.Null();
              acceptVerbs.Length.Should().Be(1);
          }
        

        【讨论】:

          猜你喜欢
          • 2011-01-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-28
          • 1970-01-01
          • 1970-01-01
          • 2016-04-24
          相关资源
          最近更新 更多