2

MVCのコントローラーで簡単なテストを実行しようとしています。このコントローラーは、xValとDataAnnotationsを使用して入力を検証します。テストを実行すると(Resharper、NUnitスタンドアロン、またはTestDriven.Netを介してNUnitを使用)、適切なエラーメッセージなしでランナーがクラッシュします。イベントログには、ランナーが障害のあるアプリケーションであるという、かなり一般的な.NETRuntime2.0エラーレポートメッセージが含まれています。

このエラーは、ModelState.IsValidの呼び出しが原因で発生します(これを取り出すと正常に実行されるため、これはわかっています)。また、クラッシュは、テストを正常に実行した場合にのみ発生します。テストをデバッグモードで実行すると、正常に機能します。

xValへの参照を削除し、ModelState.AddModelErrorを使用してmodelstateにエラーを設定しても、クラッシュしません。

以下は、テスト対象のコントローラーとテストクラスです。ここで何かおかしいことがわかりますか?

テスト中のコントローラー

using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;
using xVal.ServerSide;

namespace TestModelState.Controllers
{
    public class ThingController : Controller
    {
        [HttpPost]
        public ActionResult Create(Thing thing)
        {
            try
            {
                var errors = DataAnnotationsValidationRunner.GetErrors(thing);
                if (errors.Any())
                {
                    throw new RulesException(errors);
                }
            }
            catch (RulesException ex)
            {
                ex.AddModelStateErrors(ModelState, "thing");
            }
            if (ModelState.IsValid)
            {
                // Do some save stuff here
                return RedirectToAction("Index");
            }
            else
            {
                return View();
            }
        }
    }

    public class Thing
    {
        [Required]
        public string Name { get; set; }
    }

    internal static class DataAnnotationsValidationRunner
    {
        public static IEnumerable<ErrorInfo> GetErrors(object instance)
        {
            return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>()
                   from attribute in prop.Attributes.OfType<ValidationAttribute>()
                   where !attribute.IsValid(prop.GetValue(instance))
                   select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance);
        }
    }
}

テストクラス

using System.Web.Mvc;
using NUnit.Framework;
using TestModelState.Controllers;

namespace TestModelState.Tests
{
    [TestFixture]
    public class ThingControllerTests
    {
        [Test]
        public void Create_InvalidThing_SetsModelState()
        {
            // Arrange
            var thingController = new ThingController();
            var thing = new Thing();

            // Act
            var result = thingController.Create(thing);

            // Assert
            var viewResult = (ViewResult)result;
            Assert.IsFalse(viewResult.ViewData.ModelState.IsValid);
        }
    }
}

バージョン-ASP.NetMVC-2.0.0.0、NUnit-2.5.3.9345、xVal-1.0.0.0

更新 代わりに次のステートメントを使用すると(ModelState.IsValidが内部で実行していることです)、クラッシュは発生しません...

var modelStateIsValid = ModelState.Values.All(ms => ms.Errors.Count == 0);

それでもModelState.IsValidを使用したいのですが、少なくともこれは回避策です。

4

1 に答える 1

0

ModelState.IsValid はコントローラーによって設定されるのではなく、モデル バインディング フレームワークによって設定されます。モデル バインディング フレームワークは、着信 HTTP 要求を処理するときにのみ起動されます。上記のようにコントローラ アクションを明示的に呼び出すと、モデル バインディングが発生しないため、ModelState 全体が不確定な状態になります。あなたにはいくつかの方法があります

  1. この SO question - How can I test ModelState?で与えられているように、テストでモデルバインディング全体を模倣してください。

  2. この SO question - Unit tests on MVC validation に示されているように、コントローラ アクションで TryUpdateModel メソッドを使用できます。

  3. モデルの属性ベースの検証をテストする個別の単体テストを記述します。このためには、属性ベースの検証へのアプローチを変更する必要があります。詳細については、この記事をお読みください - http://jesschadwick.blogspot.com/2009/04/cleaner-validation-with-aspnet-mvc.html

于 2011-10-05T05:05:07.163 に答える