2017-10-05 8 views
0

私は偉大なFluentValidationライブラリを使用しており、ユニットテストでバリデータを使用しています。 ShouldHaveValidationErrorFor拡張メソッドを使用してテストhttps://github.com/JeremySkinner/FluentValidation/wiki/g.-TestingFluentValidationテストでNullが処理されない

を、私はできるだけこのwikiページの例を以下している(しかし、私はxUnitのを使用しています)。

NullReferenceExceptionテストが失敗しました。しかし、それはまさに私がテストしようとしているものです。

ここにありますが、私のコードです:

バリ:

public class ChangeEmailRequestInputModelValidator : AbstractValidator<ChangeEmailRequestInputModel> 
{ 
    public ChangeEmailRequestInputModelValidator() 
    { 
     RuleFor(x => x.NewEmail) 
      .NotEmpty(); 

     RuleFor(m => m.NewEmail.Trim()) 
      .EmailAddress() 
      .When(m => m.NewEmail != null) 
      .WithMessage(ValidationConstants.SymbolIsNotAValidEmailAddress, x => x.NewEmail) 
      .WithName("NewEmail"); 

     RuleFor(m => m.NewEmailConfirm.Trim()) 
      .Cascade(CascadeMode.Continue) 
      .NotEmpty().WithMessage("Confirm New Email field cannot be empty.") 
      .Equal(m => m.NewEmail.Trim()).WithMessage("Confirm New Email field must be equal to the New Email."); 
    } 
} 

テスト:

public class ChangeEmailRequestInputModelValidatorTests 
{ 
    [Fact] 
    public void Errors_Where_NewEmail_Is_Null() 
    { 
     var val = new ChangeEmailRequestInputModelValidator(); 

     val.ShouldHaveValidationErrorFor(v => v.NewEmail, null as string);    
    } 
} 

なぜこれが起こっているすべてのアイデア?私は何か間違っている必要がありますが、それは私がうんざりしている例と似ています。

答えて

1

あなたは3つのルールを設定している:

  1. NEWEMAILがNEWEMAILがnullでない場合は、それをトリミングし、それが有効なEメールアドレス
  2. トリムNewEmailConfirmだ確実
  3. nullにすることはできません、それが空ではないことを確認それをトリムされたNewEmailと比較し、一致することを確認します。

問題を引き起こすのは3番目のルールです。 FluentValidationがフード内で動作する方法は、WhenまたはUnlessを使用しない限り、評価される最初の式がRuleForに渡される式であることを意味します。これらの両方がルールを逆戻りし、条件付きメソッドに渡される述語または逆述語を適用します。

本質的に、バリデーターは起動し、3つのルールのうちの2つを通過してから、3番目のルールの評価を開始します。テストフィクスチャはNewEmailConfirmの値を設定していないので、式チェーンの評価を開始し、最初の式であるm => m.NewEmailConfirm.Trim()をヒットします。これが爆発します。あなたはこれを防ぐために何ができるか

は以下の通りです:

[Fact] 
public void Errors_Where_NewEmail_Is_Null() 
{ 
    var sut = new ChangeEmailRequestInputModelValidator(); 
    sut.ShouldHaveValidationErrorFor(v => v.NewEmail, new ChangeEmailRequestInputModel { NewEmail = null, NewEmailConfirm = "[email protected]" }); 
} 

これはその最初の式に爆破しないように右のビットを使用して、クラス・アンダー・検証をインスタンス化します。あなたが今直面する問題は、ある時点で.Equal(m => m.NewEmail.Trim())を打つことになるということです。治具はルール2をテストするためにこれを明示的にnullに設定しているので、ルール3はまだ再構成する必要があります。

私は次のことをお勧めします:

public ChangeEmailRequestInputModelValidator(){ 

    RuleFor(m => m.NewEmail) 
     .Cascade(CascadeMode.StopOnFirstFailure) 
     .NotEmpty() 
     .WithMessage("Email is a required field.") 
     .EmailAddress() 
     .WithMessage(
      ValidationConstants.SymbolIsNotAValidEmailAddress, x => x.NewEmail) 
     .WithName("NewEmail"); 

    RuleFor(m => m.NewEmailConfirm) 
     .NotEmpty() 
     .WithMessage("Confirm New Email field cannot be empty."); 

    RuleFor(m => m) 
     .Must(HaveMatchingEmailAndConfirmEmail) 
     .WithMessage("Confirm New Email field must be equal to the New Email."); 
} 

private bool HaveMatchingEmailAndConfirmEmail(ChangeEmailRequestInputModel model) 
{ 
    return model.NewEmail?.Trim() == model.NewEmailConfirm?.Trim(); 
} 

上記は、まだ互いに独立して、あなたの特性の両方を検証するために管理。次に、両方のプロパティをお互いに照合して、ヌル合体演算子を使用して明示的なヌルチェックを回避します。

+0

ありがとうございました。それは完全に意味をなさない。私は問題が自分のコードであることを知っていた。ただそれを見ることができませんでした。 – onefootswill

+0

これを再検討して申し訳ありませんが、値がnullのときにコードが爆発するのを防ぐために条件を使用しないでください。私は、トリムは、いつ実行されるのを防ぐのだろうと期待していませんでした。 – onefootswill

+0

あなたは正しいです、あなたは私の答えを受け入れることができますか?それを爆発している*実際の理由で更新しますか? –

関連する問題