2017-05-30 5 views
1

私が使用しているインターフェース用のカスタムHamcrest matcherを作成しました。カスタムのHamcrest Matcherでの変数のキャッシュ

マッチャがTypeSafeMatcherのインスタンスであり、それは以下の3つの方法よりも優先されます:私は「クラスvoid

  • TypeSafeMatcher#matchesSafely(T item)boolean
  • TypeSafeMatcher#describeMismatchSafely(T item, Description mismatchDescription)void
  • TypeSafeMatcher#describeTo(Description description)をmのマッチングが特定の型の検証を処理するo fオブジェクト。それは外部のライブラリから来るので、私はそれを単に変更することはできません。このクラスを呼び出すValidationSubject

    すべてのインスタンスValidationSubjectこのクラスは、実行される検証の背後にあるいくつかのロジックを定義します。これはvalidationDataは、プログラマがValidationSubject

    public class Foo implements ValidationSubject { 
    
        private String state; 
    
        private Map<String, Baz> moreState; 
    
        // constructor, methods affecting the state 
    
        // this method is required by ValidationSubject 
        @Override 
        public void validate(ValidationData validationData) { 
         /* 
         * call methods on validationData based on the state 
         * of the object 
         */ 
        } 
    } 
    

    を実装したクラスのオブジェクトの状態に基づいて検証エラーを報告することができますビルダー型のオブジェクトである私がテストするために私のマッチャーを使用していValidationSubject#validate(ValidationData validationData)を実装することによって行われますFooなどの各具体的なクラスに実装された検証ロジック。

    これを行うには、各テストケースでValidationDataのインスタンスをスタブ/モック/スパイする必要があり、テスト対象のロジックによって、ValidationDataオブジェクトの状態がどのように変更されたかを確認してください。それは多くの定型文です。私は離れて

    assertThat(testedValidationSubject, hasValidationErrors("Illegal character in name", "Description exceeds 200 words", "Age cannot be negative")); 
    

    この場合、私が本当にhasValidationErrorsマッチャーの引数に対して一致していますが、テスト対象の被験体がValidationDataオブジェクトに格納されている文字列値のセットである抽象への私のマッチャーをしたいです。

    これらの値を抽出するには、少しのコードが必要です。

    return new TypeSafeMatcher<ValidationSubject>() { 
    
        @Override 
        protected boolean matchesSafely(ValidationSubject item) { 
         // this calls the relevant methods on 'item' internally 
         Validator validator = new Validator(item); 
         List<ValidationMessage> errorMessages = validator.getErrorMessageGroup() 
           .getMessages(); 
         Set<String> actualMessages = errorMessages.stream().map(e -> e.getMessage()) 
           .collect(Collectors.toSet()); 
         Set<String> expectedMessages = Stream.of(expectedErrors).collect(Collectors.toSet()); 
         Set<String> missingMessages = SetUtils.difference(expectedMessages, actualMessages); 
         Set<String> unexpectedMessages = SetUtils.difference(actualMessages, expectedMessages); 
         return SetUtils.union(unexpectedMessages, missingMessages).isEmpty(); 
        } 
    
        @Override 
        public void describeMismatchSafely(final ValidationSubject item, final Description description) { 
             // this calls the relevant methods on 'item' internally 
         Validator validator = new Validator(item); 
         List<ValidationMessage> errorMessages = validator.getErrorMessageGroup() 
           .getMessages(); 
         Set<String> actualMessages = errorMessages.stream().map(e -> e.getMessage()) 
           .collect(Collectors.toSet()); 
         Set<String> expectedMessages = Stream.of(expectedErrors).collect(Collectors.toSet()); 
         Set<String> missingMessages = SetUtils.difference(expectedMessages, actualMessages); 
         Set<String> unexpectedMessages = SetUtils.difference(actualMessages, expectedMessages); 
         description.appendText("Validation errors were missing or unexpected\n") 
           .appendValueList("\tSupefluous messages: ", ", ", "\n", unexpectedMessages.toArray()) 
           .appendValueList("\tMissing messages: ", ", ", "\n", missingMessages.toArray()); 
        } 
    
        @Override 
        public void describeTo(Description description) { 
         description.appendText("validation should result in the expected errors"); 
        } 
    } 
    

    コードのこの作品は、ライン・バイ・ライン繰り返される:

    Validator validator = new Validator(item); 
    List<ValidationMessage> errorMessages = validator.getErrorMessageGroup() 
         .getMessages(); 
    Set<String> actualMessages = errorMessages.stream().map(e -> e.getMessage()) 
         .collect(Collectors.toSet()); 
    Set<String> expectedMessages = Stream.of(expectedErrors).collect(Collectors.toSet()); 
    Set<String> missingMessages = SetUtils.difference(expectedMessages, actualMessages); 
    Set<String> unexpectedMessages = SetUtils.difference(actualMessages, expectedMessages); 
    

    私は(のペアを返すメソッドやラムダ式でこの作品をラップすることにより、重複を取り除くことができます私が必要とするブール値または文字列を計算する関数をパラメータとして設定または受け入れる)。理想的には、はこれを1回だけ実行したい。

    は私がdescribemisMatchSafelyによって両方matchesSafelyとメッセージ出力の結果を把握するitemを必要とするが、各時間は、それがパラメータとして渡されます。これは静的メソッドhasValidationErrorsのパラメータではないので、結果をいくつかの変数にキャッシュするためのきれいな方法はわかりません。

    これらのメソッドの1つでこのコードを実行してフィールドにキャッシュする可能性がありますが、the Javadoc for TypeSafeMatcherは最初に実行されるメソッドが保証されていないようです。

答えて

0

あなたがしようとしていることを理解している場合は、TypeSafeDiagnosingMatcherによって提供される機能を探しています。 TypeSafeMatcherの代わりにそれを拡張してみてください:

return new TypeSafeDiagnosingMatcher<ValidationSubject>() { 

    @Override 
    protected boolean matchesSafely(ValidationSubject item, Description mismatchDescription) { 
     // this calls the relevant methods on 'item' internally 
     Validator validator = new Validator(item); 
     List<ValidationMessage> errorMessages = validator.getErrorMessageGroup() 
       .getMessages(); 
     Set<String> actualMessages = errorMessages.stream().map(e -> e.getMessage()) 
       .collect(Collectors.toSet()); 
     Set<String> expectedMessages = Stream.of(expectedErrors).collect(Collectors.toSet()); 
     Set<String> missingMessages = SetUtils.difference(expectedMessages, actualMessages); 
     Set<String> unexpectedMessages = SetUtils.difference(actualMessages, expectedMessages); 
     mismatchDescription.appendText("Validation errors were missing or unexpected\n") 
       .appendValueList("\tSuperfluous messages: ", ", ", "\n", unexpectedMessages.toArray()) 
       .appendValueList("\tMissing messages: ", ", ", "\n", missingMessages.toArray()); 
     return SetUtils.union(unexpectedMessages, missingMessages).isEmpty(); 
    } 

    @Override 
    public void describeTo(Description description) { 
     description.appendText("validation should result in the expected errors"); 
    } 
} 
関連する問題