web-dev-qa-db-ja.com

ModelStateのテストは、asp.netmvcで常に有効です。

コントローラのアクションをテストするとき、ModelStateは常に有効です。

public class Product
{
    public int Id { get; set; }

    [Required]
    [StringLength(10)]
    public string Name { get; set; }

    [Required]
    public string Description { get; set; }

    [Required]
    public decimal Price { get; set; }
}

そして私のコントローラー。

public class ProductController : Controller
{
      [HttpPost]
      public ActionResult Create(Product product)
      {
            if (ModelState.IsValid)
            {
                   // Do some creating logic...
                   return RedirectToAction("Display");
            }

             return View(product);              
      }
 }

そしてテスト:

[Test]
public TestInvalidProduct()
{
     var product = new Product();
     var controller = new ProductController();
     controller.Create(product);
     //controller.ModelState.IsValid == true
}

製品に名前、説明、価格がないのに、modelStateが有効なのはなぜですか?

検証は、投稿されたデータがビューモデルにバインドされたときに行われます。次に、ビューモデルがコントローラーに渡されます。パート1をスキップして、ビューモデルをコントローラーに直接渡します。

を使用してビューモデルを手動で検証できます

System.ComponentModel.DataAnnotations.Validator.TryValidateObject()
18
Dan

私は同じ問題に遭遇しました そしてここで受け入れられた答えは「検証なし」の問題を解決しましたが、それは私に大きな否定的な側面を残しました:検証があったときに例外をスローします単に_ModelState.Invalid_をfalseに設定する代わりにエラーが発生します。

これはWebApi 2でのみテストしたため、どのプロジェクトでこれを使用できるかわかりませんが、渡されたオブジェクトの検証を強制し、設定するだけのメソッド ApiController.Validate(object) があります。 _ModelState.IsValid_からfalse。さらに、Configurationプロパティもインスタンス化する必要があります。

このコードを単体テストに追加すると、次のように機能しました。

_userController.Configuration = new HttpConfiguration();
userController.Validate(addressInfo);
_
10
Jeroen Vannevel

別の注意点。コントローラが返すものと、返されたActionResultが期待どおりであることを実際にテストする必要があります。 ModelBinderのテストは個別に行う必要があります。

たとえば、カスタムモデルバインダーに切り替えたいとします。 ModelBinderテストを、作成している新しいModelBinderに再利用できます。ビジネスルールが同じままの場合は、同じテストを直接再利用できるはずです。ただし、ControllerテストとModelBinderテストを組み合わせてテストが失敗した場合、問題がControllerにあるのかModelBinderにあるのかわかりません。

次のようなものをバインドするモデルをテストするとします。

[Test]
public void Date_Can_Be_Pulled_Via_Provided_Month_Day_Year()
{
    // Arrange
    var formCollection = new NameValueCollection { 
        { "foo.month", "2" },
        { "foo.day", "12" },
        { "foo.year", "1964" }
    };

    var valueProvider = new NameValueCollectionValueProvider(formCollection, null);
    var modelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(FwpUser));

    var bindingContext = new ModelBindingContext
    {
        ModelName = "foo",
        ValueProvider = valueProvider,
        ModelMetadata = modelMetadata
    };

    DateAndTimeModelBinder b = new DateAndTimeModelBinder { Month = "month", Day = "day", Year = "year" };
    ControllerContext controllerContext = new ControllerContext();

    // Act
    DateTime result = (DateTime)b.BindModel(controllerContext, bindingContext);

    // Assert
    Assert.AreEqual(DateTime.Parse("1964-02-12 12:00:00 am"), result);
}

これで、モデルが正しくバインドされたことがわかったので、別のテストでコントローラーを使用してモデルのテストを続行し、正しい結果が返されるかどうかを確認できます。さらに、バインドされたモデル値を使用して、検証属性をテストできます。

このようにして、アプリケーションが爆発した場合に、実際にどのレベルでそれを実行するかを明らかにするテストの完全なセットを取得できます。 ModelBinding、Controller、またはValidation。

4
  1. コントローラクラスのインスタンスを作成します。
  2. モデル状態を追加し、モデル状態を追加した後に呼び出す
  3. modelStateは常にfalseを与えます

    controller.ModelState.AddModelError("key", "error message");
    
    var invalidStateResult = _controller.Index();
    
    Assert.IsNotNull(invalidStateResult);
    
3
ಅನಿಲ್

使用する controller.UpdateModelまたはcontroller.TryUpdateModelコントローラーの現在のValueProviderを使用してデータをバインドし、ModelState.IsValidかどうかを確認する前にモデルバインドの検証をトリガーします

2

検証アクションの動作をテストする場合は、ModelStateErrorを追加するだけです。

ModelState.AddModelError("Password", "The Password field is required");
0
Felix