24

コントローラーのアクションをテストするとき、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 が有効なのですか?

4

7 に答える 7

18

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

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

System.ComponentModel.DataAnnotations.Validator.TryValidateObject()
于 2011-11-17T10:01:17.133 に答える
10

私は同じ問題に遭遇しました。ここで受け入れられた回答は「検証なし」の問題を解決しましたが、大きなマイナス面が残りました.単にに設定ModelState.Invalidするのではなく、検証エラーが発生すると例外がスローされfalseます.

私はこれを Web Api 2 でのみテストしたので、どのプロジェクトでこれが利用可能になるかはわかりませんがApiController.Validate(object)、渡されたオブジェクトの検証を強制し、にのみを設定するModelState.IsValidメソッドがありますfalse。さらに、プロパティをインスタンス化する必要もありConfigurationます。

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

userController.Configuration = new HttpConfiguration();
userController.Validate(addressInfo);
于 2014-11-05T17:26:18.540 に答える
4

別の注意事項。コントローラーが返すものと、返された 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、コントローラー、または検証。

于 2012-12-14T16:23:32.563 に答える
3
  1. コントローラー クラスのインスタンスを作成します。
  2. モデル状態を追加して呼び出す モデル状態を追加した後
  3. modelState は常に false を返します

    controller.ModelState.AddModelError("key", "error message");
    
    var invalidStateResult = _controller.Index();
    
    Assert.IsNotNull(invalidStateResult);
    
于 2015-05-24T06:16:35.293 に答える
2

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

于 2011-11-22T22:49:03.383 に答える
0

検証アクションの動作をテストしたい場合は、単純に ModelStateError を追加できます。

ModelState.AddModelError("Password", "The Password field is required");
于 2012-08-28T05:02:17.240 に答える
-2

コントローラーを試す。controller.ModelState.IsValid の代わりにViewModel .ModelState.IsValid。

于 2011-11-17T09:54:54.727 に答える