2017-01-26 12 views
1

私はこのC#の世界で非常に初心者です。C#MVCモデルは、ユニットテストコントローラアクションのときに常に有効です

このモデルクラスがあります:

public class Fund 
    { 
     [Required] 
     public int id { get; set; } 
     [Required] 
     public string name { get; set; } 
     [Required] 
     public string nickname { get; set; } 
    } 

[Required]注釈がすべてのプロパティを介してではあるが、同様のインスタンス:

if (ModelState.IsValid) 
{ 
    // do stuff 
} 

Fund f = new Fund(); 
f.name = "test name"; 
f.nickname = "test ninckname"; 

はいつものように、テストに合格

モデルを設定して、そのようなインスタンスがiで渡されないようにするにはどうすればいいですか? n ModelState.IsValidテスト?以下のような

その他の事例:

Fund f1 = new Fund(); 
f1.id = 3; 
f1.nickname = "test ninckname"; 

Fund f2 = new Fund(); 
f2.id = 3; 
f2.name = "test name"; 

は、テストに合格しています。

EDIT:

ModelState.IsValidは、コントローラ内部で、私は実際にコントローラをテストしています。

EDIT 2:コントローラのメソッドシグネチャである

[HttpPatch] 
public ActionResult EditFund(Fund fund) 

EDIT 3:

[TestMethod] 
public void TestEditInvalidFund() 
{ 
    // Arrange 
    FundController controller = new FundController(); 
    controller.ControllerContext = TestModelHelper.AdminControllerContext(); 
    var _fund = new Mock<IFund>(); 
    _fund.SetupGet(f => f.id).Returns(1); 
    //_fund.SetupGet(f => f.name).Returns("Fund name"); 
    _fund.SetupGet(f => f.nickname).Returns("Fund nickname"); 
    _fund.Setup(f => f.Edit()).Callback(() => {}).Verifiable(); 

    // Act 
    var result = (JsonResult)controller.EditFund(_fund.Object); 

    // Assert 
    SimpleMessage resultMessage = m_serializer.Deserialize<SimpleMessage>(m_serializer.Serialize(result.Data)); 
    Assert.IsNotNull(resultMessage.status, "JSON record does not contain 'status' required property."); 
    Assert.IsTrue(resultMessage.status.Equals("fail"), "status must be 'fail'"); 
} 

そして、それは次のようになります。私の全体の試験方法である コントローラ全体の方法:

[HttpPatch] 
public ActionResult EditFund(IFund _fund) 
{ 
    try 
    { 
     if (ModelState.IsValid) 
     { 
      //_fund.Edit(); 
     } 
     else 
     { 
      string error_messages = ""; 
      foreach (var e in ModelState.Select(x => x.Value.Errors).Where(y => y.Count > 0).ToList()) 
      { 
       error_messages += e[0].ErrorMessage + "\n"; 
      } 
      throw new Exception(error_messages); 
     } 
     return MessageHelper(@Resources.Global.success, @Resources.Funds.success_editing_fund, "success"); 
    } 
    catch (Exception err) 
    { 
     return ErrorHelper(@Resources.Global.error, @Resources.Funds.error_editing_fund, err.Message); 
    } 
} 
+0

は、なぜあなたは第一例が有効でないと思うだろう - あなたは ''名 'の値を提供してきました'nickname'と' int'のデフォルトは '0'でも有効です。あなたがintに無効なものにしたいなら、それをヌル値にして '[Required]'属性を追加してください。 –

+0

@ChrisFCarroll、コントローラーの中にあります。 –

+0

コードスニペットはコントローラからのもので、ユニットテストをしようとしていますか? –

答えて

2

ユニットテストModelState.IsValidを使用することはできません。まあ、できますが、それを行うには余分なコードが必要です。それはまさに理想的ではありません。ここで

はgithubの上の私のコードです:https://www.nuget.org/packages/TestBase-Mvc/

そして、ここで私はそれを使用する方法は次のとおりです:WithModelStateIsInvalid<TController>()

そして、ここではそれがでますNuGetパッケージです

UnitUnderTest 
    .WithModelStateIsInValid() 
    .Action(model) 
    .ShouldBeViewResult() 
    .ShouldBeAnInvalidModel(); 

-------- ---------------------------------

あなたがユニットを作ることができない理由それはModelBindingのステップでモデル検証が行われてから、コントローラのアクションが呼び出される前にになります。

モデル検証の失敗をシミュレートするには、アクションを呼び出す前に、ユニットテストコードでcontroller.ModelStateを '手動で'無効にするのが最も簡単な方法です。これは拡張メソッドが何をするかですが、実際にはそれだけで1行だ:

controller.ModelState.AddModelError("FieldName", @"error message") 

(より洗練された拡張メソッドは、おそらくあなたがモデルのキーが無効であるかを指定聞かせPRSは常に歓迎します。)。

+0

ありがとう、それは働いた! GitHub上のコードについては、それは非常に高度ですが、私は理解できませんが、私がよりスマートになったらそれを保つつもりです。 –

+0

:-) Ta。ある日、私はそれを単純化します。 –

2
[Required] 
public int id { get; set; } 

intはNULL可能ではないので、これは常に有効になります。デフォルト値は0です。

+0

私は見るが、 'name'と' nickname'のような他のプロパティについてはどうですか? –

+0

@ThiagoMelo文字列はnull型であるため、渡すには[必須]属性の値を指定する必要があります。 – SledgeHammer

+0

小さなスニペットを提供できますか?どのように私はそれらのための値を指定する必要がありますか? –

0

わからない、それが有効な取得しますが、明示的でモデルを再検証しようとすることができる理由:

TryValidateModel(fund) 
関連する問題