TDD - 测试ASP.NET MVC中的业务规则/验证

时间:2010-03-29 10:31:09

标签: asp.net-mvc tdd modelstate

我正在使用尖锐的架构,因此我可以在单元测试和/或TDD期间轻松使用模拟等。我有非常复杂的业务规则,并希望在控制器级别测试它们。我只是想知道其他人是怎么做到的?

对我来说,验证测试业务规则分为三个层次:

(1)物业等级(例如物业需要) (2)内部财产水平(例如开始日期&结束日期) (3)持久性等级(例如名称是唯一的,父母不能是孩子的孩子)

我的验证框架也会为属性分配错误。我只是想知道其他人在做什么?您是否为每个业务规则编写测试并检查是否将正确的错误消息分配给正确的属性(即查看ASP.MVC ModelState)?

我希望我的问题有道理。非常感谢!

祝福,

基督教

1 个答案:

答案 0 :(得分:0)

我通常把它分成两部分:

  1. 测试控制器在模型有效时和不存在时是否正常运行。
  2. 测试模型是否与规则引擎组合产生正确的错误消息。
  3. 基本原理是当控制器对错误行为正确,并且模型本身正确验证时,应用程序将正常运行。测试设置也会更简单。

    在最简单的情况下,对于帖子我们可能希望控制器在一切正常时重定向到结果页面,但在有验证错误时重新显示相同的视图:

      [TestClass]
        public class Maintaining_todo_list
        {
            private TodoController controller;
    
            [TestInitialize]
            public void Setup()
            {
                controller = new TodoController {ControllerContext = new ControllerContext()};
            }
    
            [TestMethod]
            public void Valid_update_should_redirect_to_list()
            {
                var result = controller.Edit(1, new TodoItem {Text = "todo"});
                result.ShouldRedirectTo("list");
            }
    
            [TestMethod]
            public void Invalid_update_should_display_same_view()
            {
                var result = controller.Edit(1, new TodoItem {Text = ""});
                result.ShouldDisplayDefaultView();
            }
        }
    

    模型可能会因各种消息而以各种方式失败:

       [TestClass]
        public class Validating_todo_item
        {
            [TestMethod]
            public void Text_cannot_be_empty()
            {
                var todo = new TodoItem {Text = ""};
                todo.ShouldContainValidationMessage("Text cannot be empty");
            }
    
            [TestMethod]
            public void Text_cannot_contain_more_than_50_characters()
            {
                var todo = new TodoItem { Text = new string('a', 51) };
                todo.ShouldContainValidationMessage("Text cannot contain more than 50 characters");
            }
    
            [TestMethod]
            public void Valid_items()
            {
                new TodoItem { Text = new string('a', 1) }.ShouldBeValid();
                new TodoItem { Text = new string('a', 50) }.ShouldBeValid();
            }
        }
    

    (为了完整起见,这里是测试助手)

     internal static class AssertionHelpers
        {
            public static void ShouldRedirectTo(this ActionResult result, string action)
            {
                var redirect = result as RedirectToRouteResult;
    
                Assert.IsNotNull(redirect);
                Assert.AreEqual(action, redirect.RouteValues["action"]);
                Assert.IsNull(redirect.RouteValues["controller"]);
            }
    
            public static void ShouldDisplayDefaultView(this ActionResult result)
            {
                var view = result as ViewResult;
    
                Assert.IsNotNull(view);
                Assert.AreEqual("", view.ViewName);
            }
    
            public static void ShouldContainValidationMessage(this TodoItem todo, string message)
            {
                var context = new ValidationContext(todo, null, null);
                var results = new List<ValidationResult>();
    
                Validator.TryValidateObject(todo, context, results, true);
    
                var errors = results.Select(result => result.ErrorMessage);
    
                foreach (var error in errors)
                {
                    Console.Out.WriteLine(error);
                }
    
                Assert.IsTrue(errors.Contains(message));
            }
    
            public static void ShouldBeValid(this TodoItem todo)
            {
                var context = new ValidationContext(todo, null, null);
                var results = new List<ValidationResult>();
                var isValid = Validator.TryValidateObject(todo, context, results, true);
                Assert.IsTrue(isValid);
            }
        }