コントローラのアクションをテストするとき、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()
私は同じ問題に遭遇しました そしてここで受け入れられた答えは「検証なし」の問題を解決しましたが、それは私に大きな否定的な側面を残しました:検証があったときに例外をスローします単に_ModelState.Invalid
_をfalse
に設定する代わりにエラーが発生します。
これはWebApi 2でのみテストしたため、どのプロジェクトでこれを使用できるかわかりませんが、渡されたオブジェクトの検証を強制し、設定するだけのメソッド ApiController.Validate(object)
があります。 _ModelState.IsValid
_からfalse
。さらに、Configuration
プロパティもインスタンス化する必要があります。
このコードを単体テストに追加すると、次のように機能しました。
_userController.Configuration = new HttpConfiguration();
userController.Validate(addressInfo);
_
別の注意点。コントローラが返すものと、返された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。
modelStateは常にfalseを与えます
controller.ModelState.AddModelError("key", "error message");
var invalidStateResult = _controller.Index();
Assert.IsNotNull(invalidStateResult);
使用する controller.UpdateModel
またはcontroller.TryUpdateModel
コントローラーの現在のValueProviderを使用してデータをバインドし、ModelState.IsValidかどうかを確認する前にモデルバインドの検証をトリガーします
検証アクションの動作をテストする場合は、ModelStateErrorを追加するだけです。
ModelState.AddModelError("Password", "The Password field is required");