3

單元測試控制器動作HttpAcceptAttribute動詞的最佳方式是什麼?測試MVC控制器動作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)); 
} 

感謝 的Mac

回答

3

無反射和魔術字符串,方便沒有打破單元測試來命名控制器和控制方法:

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

有趣,很乾淨的方法,非常感謝 – 2009-10-18 18:42:56

1
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); 
} 
+0

看起來不錯。謝謝 儘管進一步改進了這個想法,你認爲有一種方法可以讓它更通用:允許傳入一個HttpVerbs數組,並讓方法聲明只有HttpVerbs是完全匹配的,或者是過度殺傷和單獨的發佈,獲取,刪除,放置或組合它們的方法就足夠了? 理想情況下,我想能夠這樣稱呼它: MvcAssert.HasHttpVerbs(controller,actionName,paramTypes,HttpVerbs []); – 2009-10-18 14:42:06

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

    } 

} 
+0

非常好,謝謝Mehdi – 2009-10-18 18:42:17

0

有點修改版本Darin的解決方案。

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