具有MVC模型验证问题的规范

时间:2011-05-26 14:02:21

标签: asp.net-mvc-2 nunit moq specflow

当我学习SpecFlow时,我正在使用Specflow,nunit和moq来测试默认的MVC2应用程序注册。

我有以下步骤来检查是否还没有输入用户名和密码。

步骤

[Given(@"The user has not entered the username")]
        public void GivenTheUserHasNotEnteredTheUsername()
        {   
            _registerModel = new RegisterModel
            {
                UserName = null,
                Email = "test@dummy.com",
                Password = "test123",
                ConfirmPassword = "test123"
            };      
        }

[Given(@"The user has not entered the password")]
        public void GivenTheUserHasNotEnteredThePassword()
        {
            _registerModel = new RegisterModel
            {
                UserName = "user" + new Random(1000).NextDouble().ToString(),
                Email = "test@dummy.com",
                Password = string.Empty,
                ConfirmPassword = "test123"
            };  
        }

[When(@"He Clicks on Register button")]
        public void WhenHeClicksOnRegisterButton ()
        {
            _controller.ValidateModel(_registerModel);
            _result = _controller.Register(_registerModel);
        }

[Then(@"He should be shown the error message ""(.*)""  ""(.*)""")]
        public void ThenHeShouldBeShownTheErrorMessage(string errorMessage, string field)
        {
            Assert.IsInstanceOf<ViewResult>(_result);
            var view = _result as ViewResult;
            Assert.IsNotNull(view);
            Assert.IsFalse(_controller.ModelState.IsValid);
            Assert.IsFalse(view.ViewData.ModelState.IsValidField(field));
            Assert.IsTrue(_controller.ViewData.ModelState.ContainsKey(field));          

            Assert.AreEqual(errorMessage,
            _controller.ModelState[field].Errors[0].ErrorMessage);
        }

强制验证的扩展方法

public static class Extensions
    {
        public static void ValidateModel<T> ( this Controller controller, T modelObject )
        {
            if (controller.ControllerContext == null)
                controller.ControllerContext = new ControllerContext();

            Type type = controller.GetType();
            MethodInfo tryValidateModelMethod =
                type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(
                    mi => mi.Name == "TryValidateModel" && mi.GetParameters().Count() == 1).First();

            tryValidateModelMethod.Invoke(controller, new object[] { modelObject });
        }
    }`

我不明白为什么密码丢失测试在以下几行失败。

    Assert.IsFalse(view.ViewData.ModelState.IsValidField(field));
    Assert.IsTrue(_controller.ViewData.ModelState.ContainsKey(field));

我注意到返回的错误消息是密码和ConfirmPassword不匹配,但我不明白为什么所有其他测试,包括丢失确认密码测试(与丢失的密码测试相同),他们工作正常。 / p>

有什么想法吗?

功能

  • 场景:如果缺少用户名,则注册应返回错误
  • 鉴于用户尚未输入用户名
  • 当他点击注册按钮
  • 然后他应该看到错误 消息“用户名字段是必需的。” “用户名”

  • 场景:如果缺少密码,注册应返回错误

  • 鉴于用户尚未进入 密码
  • 当他点击注册按钮
  • 然后他应该看到错误信息“'密码'必须至少 6个字符长。“”密码“

更新 好吧,似乎帐户模型中的ValidatePasswordLengthAttribute无法初始化Membership.Provider,因为我的app.config中没有连接字符串。 Pembership.Provider现在是否连接到会员DB?

我添加了连接字符串,但现在测试通过了50%的时间,因为它返回了两个错误:

  • 需要密码
  • 密码必须为6个字符。

问题是每次都不会以相同的顺序返回它们,所以测试是不稳定的。 如何重写我的场景并测试以解决这个问题?我仍然可以保留一个“然后”方法,还是需要创建一个新方法?

感谢。

1 个答案:

答案 0 :(得分:0)

我不得不将AccountService的连接字符串添加到nunit使用的App.config中。这导致ValidatePasswordLengthAttribure出错。

我已经更新了Assert,它会检查正确的错误消息:

Assert.AreEqual(errorMessage, 
            _controller.ModelState[field].Errors.First(e => e.ErrorMessage == errorMessage).ErrorMessage);

仍然不确定Membership.Provider是否正在点击数据库