私が使用しているインターフェース用のカスタム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
は最初に実行されるメソッドが保証されていないようです。