ASP.NET MVC コントローラーのポストメソッド単体テスト: ModelState.IsValid は常に true です 質問する

ASP.NET MVC コントローラーのポストメソッド単体テスト: ModelState.IsValid は常に true です 質問する

ASP.NET MVC Web アプリケーションの最初の単体テストを作成しました。すべて正常に動作し、貴重な情報も得られていますが、ビュー モデルでエラーをテストできません。一部の値が入力されていない場合 (空の文字列または null) でも、ModelState.IsValid は常に 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 検証を使用しており、正常に動作しています。

ベストアンサー1

同時に 2 つの異なるものをテストしようとしています。コントローラはモデルの状態を検証する責任はなく、検証の結果に基づいて異なる動作をするだけです。したがって、コントローラの単体テストでは検証をテストすべきではなく、別のテストで行う必要があります。私の意見では、3 つの単体テストが必要です。

  1. モデルの検証が正しく行われているかどうかを検証するもの
  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
}

おすすめ記事