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