ASP.NET MVC Webアプリケーションの最初の単体テストを作成しました。すべて正常に機能し、貴重な情報を提供していますが、ビューモデルでエラーをテストすることはできません。 ModelState.IsValidは、一部の値が入力されていない場合(空の文字列またはnull)でも常にtrueです。
投稿されたデータがモデルにマッピングされたときにモデルの検証が行われ、モデルの検証を自分で行うためのコードを記述する必要があることをすでに読んでいます。
リンクされたWebページで提供されている3つの例を試しましたが、うまくいかないようです。
いくつかのコード:
私のビューモデル
...
[Required(ErrorMessageResourceName = "ErrorFirstName", ErrorMessageResourceType = typeof(Mui))]
[MaxLength(50)]
[Display(Name = "Firstname", ResourceType = typeof(Mui))]
public string FirstName { get; set; }
...
コントローラー
...
[HttpPost]
public ActionResult Index(POSViewModel model)
{
Contract contract = contractService.GetContract(model.ContractGuid.Value);
if (!contract.IsDirectDebit.ToSafe())
{
ModelState.Remove("BankName");
ModelState.Remove("BankAddress");
ModelState.Remove("BankZip");
ModelState.Remove("BankCity");
ModelState.Remove("AccountNr");
}
if (ModelState.IsValid)
{
...
contractValidationService.Create(contractValidation);
unitOfWork.SaveChanges();
return RedirectToAction("index","thanks");
}
else
{
return Index(model.ContractGuid.ToString());
}
}
単体テスト
posViewModel.FirstName = null;
posViewModel.LastName = "";
...
var modelBinder = new ModelBindingContext()
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => posViewModel, posViewModel.GetType()),
ValueProvider = new NameValueCollectionValueProvider(new System.Collections.Specialized.NameValueCollection(), CultureInfo.InvariantCulture)
};
var binder = new DefaultModelBinder().BindModel(new ControllerContext(), modelBinder);
posController.ModelState.Clear();
posController.ModelState.Merge(modelBinder.ModelState);
ActionResult result = posController.Index(posViewModel);
//Assert
mockContractValidationService.Verify(m => m.Create(It.IsAny<ContractValidation>()), Times.Never);
Assert.IsInstanceOfType(result, typeof(ViewResult));
ビューでは、控えめなJavaScript検証を使用していますが、機能します。
私はこの解決策を見つけました: SO:Validator.TryValidateObjectを使用すると検証が機能しません 提供される@Kennethの解決策と組み合わせて:
[TestMethod]
public void test_validation()
{
var sut = new POSViewModel();
// Set some properties here
var context = new ValidationContext(sut, null, null);
var results = new List<ValidationResult>();
TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(POSViewModel), typeof(POSViewModel)), typeof(POSViewModel));
var isModelStateValid = Validator.TryValidateObject(sut, context, results, true);
// Assert here
}
リソースをすべて含むクラスライブラリがある場合は、テストプロジェクトで参照することを忘れないでください。
2つの異なることを同時にテストしようとしています。コントローラーはモデルの状態を検証する責任を負いません。検証の結果に基づいて異なる動作をするだけです。そのため、コントローラーの単体テストでは検証をテストしないでください。別のテストで実行する必要があります。私の意見では、3つの単体テストが必要です。
その方法は次のとおりです。
1.モデル検証
[Test]
public void test_validation()
{
var sut = new POSViewModel();
// Set some properties here
var context = new ValidationContext(sut, null, null);
var results = new List<ValidationResult>();
var isModelStateValid =Validator.TryValidateObject(sut, context, results, true);
// Assert here
}
2.無効なモデル状態のコントローラー
[Test]
public void test_controller_with_model_error()
{
var controller = new PosController();
controller.ModelState.AddModelError("test", "test");
ActionResult result = posController.Index(new PosViewModel());
// Assert that the controller executed the right actions when the model is invalid
}
3.有効なモデル状態のコントローラー
[Test]
public void test_controller_with_valid_model()
{
var controller = new PosController();
controller.ModelState.Clear();
ActionResult result = posController.Index(new PosViewModel());
// Assert that the controller executed the right actions when the model is valid
}