对控制器动作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
答案 0 :(得分: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");
}
答案 1 :(得分: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);
}
答案 2 :(得分: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;
}
}
}
答案 3 :(得分: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);
}