C# 测试MVC控制器动作HttpAcceptAttribute谓词

C# 测试MVC控制器动作HttpAcceptAttribute谓词,c#,unit-testing,model-view-controller,xunit.net,acceptverbs,C#,Unit Testing,Model View Controller,Xunit.net,Acceptverbs,单元测试控制器操作HttpAcceptAttribute谓词的最佳方法是什么 到目前为止,我有以下内容,但它是如此丑陋,甚至一个母亲都不能爱它,不是很灵活。有更好的办法吗 [Fact] // using xUnit, mocking controller in class public void FilterControllerTestRemoveFilterByProductAttributeIsOfTypePost() { Type[] paramTypes = new[] { ty

单元测试控制器操作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));
}
[Fact]//使用xUnit,在类中模拟控制器
public void FilterController estremoveFilterByProductAttributesOfTypePost()
{
Type[]paramTypes=new[]{typeof(int)};
var method=typeof(FilterController).GetMethod(“MyMethod”,paramTypes);
var attributes=method.GetCustomAttributes(typeof(AcceptVerbsAttribute),false).Cast().SingleOrDefault();
Assert.NotNull(属性);
Assert.Equal(1,attributes.Verbs.Count());
True(attributes.Verbs.First().Equals(HttpVerbs.Post.ToString(),StringComparison.InvariantCultureIgnoreCase));
}
谢谢 Mac

使用系统;
使用System.Linq;
运用系统反思;
使用System.Web.Mvc;
使用Microsoft.VisualStudio.TestTools.UnitTesting;
命名空间mvcapapplication4.Tests
{
公共静态类mvcasert
{
公共静态MethodInfo ActionExists(控制器控制器、字符串actionName、HttpVerbs expectedVerbs、参数类型[]参数类型)
{
如果(控制器==null)
抛出新的异常(“控制器”);
if(string.IsNullOrEmpty(actionName))
抛出新的ArgumentNullException(“actionName”);
int实际值rbs=0;
MethodInfo action=controller.GetType().GetMethod(actionName,paramTypes);
Assert.IsNotNull(action,string.Format(“找不到指定的操作“{0}”,actionName));
AcceptVerbsAttribute acceptVerb=属性。GetCustomAttribute(action,typeof(AcceptVerbsAttribute))作为AcceptVerbsAttribute;
if(acceptVerb==null)
actualVerbs=(int)HttpVerbs.Get;
其他的
actualVerbs=(int)Enum.Parse(typeof(HttpVerbs),string.Join(“,”,acceptVerb.Verbs.ToArray()),true);
Assert.AreEqual(actualVerbs,(int)expectedVerbs);
返回动作;
}
}
}

无反射和魔法字符串,易于重命名控制器和方法而不破坏单元测试:

[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");
}
[TestMethod]
public void HomeController\u Index\u Action\u应该\u接受\u Post\u动词\u Only()
{
表达式=(HomeController c)=>c.Index(null);
var methodCall=expression.Body作为MethodCallExpression;
var acceptVerbs=(AcceptVerbsAttribute[])methodCall.Method.GetCustomAttributes(typeof(AcceptVerbsAttribute),false);
接受动词。不应为空(“”);
接受动词。长度。应为(1);
acceptVerbs[0]。Verbs.First()。应为(“POST”);
}

对达林的解决方案稍加修改

  [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);
  }
[事实]
public void Delete_动词(){
VerifyVerb(x=>x.Delete(null));
}
受保护的void VerifyVerb(表达式exp){
var methodCall=exp.Body作为MethodCallExpression;
var acceptVerbs=methodCall.Method
.GetCustomAttributes(typeof(TVerbType),false);
acceptVerbs.Should().Not.Be.Null();
acceptVerbs.Length.Should()为(1);
}

看起来不错。感谢您进一步完善了这个想法,您是否认为有一种方法可以使它更通用,允许传入一组HttpVerbs,并让方法断言只有HttpVerbs是完全匹配的,或者对post、get、delete、put或它们的组合使用过多和单独的方法就足够了?理想情况下,我希望能够将其命名为mvcasert.HasHttpVerbs(controller、actionName、paramTypes、HttpVerbs[]);
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;
        }

    }

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