JUnit用と言っていますがhamcrestしか使っていません。
ほとんどテストをしていないのですが、作ったことを忘れてしまいそうなので上げておきます。
使用しているライブラリは下記の通りです。
・hamcrest-core-1.3.jar
・commons-lang3-3.2.1.jar
+各ライブラリで必要なライブラリ
package my.junit.matcher;
import org.hamcrest.Matcher;
/**
* 一部のプロパティを選択してbeanの比較を行えるMatcher
*
* @author blog owner
*
* @param <T>
* 任意のクラス
*/
class BeanPropertiesMatcher<T> extends AbstractBeanPropertiesMatcher<T> {
/**
* コンストラクタ
*
* @param expected
* 予想される値
* @param properties
* 比較対象のプロパティ
*/
BeanPropertiesMatcher(T expected, String... properties) {
super();
this.expected = expected;
this.properties = properties;
}
/**
* Matcherを取得します。
*
* @param expected
* 予想される値
* @param propeties
* 比較対象のプロパティ
* @return 一部のプロパティを選択して比較を行えるMatcher
*/
public static <T> Matcher<T> equalsValueOf(T expected, String... propeties) {
return new BeanPropertiesMatcher<T>(expected, propeties);
}
}
BeanIgnorePropertiesMatcher.java
package my.junit.matcher;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.ArrayUtils;
import org.hamcrest.Matcher;
/**
* 一部のプロパティを無視してbeanの比較を行えるMatcher
*
* @author blog owner
*
* @param <T>
* 任意のクラス
*/
class BeanIgnorePropertiesMatcher<T> extends AbstractBeanPropertiesMatcher<T> {
/**
* コンストラクタ
*
* @param expected
* 予想される値
* @param ignoreProperties
* 比較対象外のプロパティ
*/
BeanIgnorePropertiesMatcher(T expected, String[] ignoreProperties) {
super();
this.expected = expected;
if(expected == null){
this.properties = new String[0];
}else{
// 全てのFieldから比較対象外のプロパティを除いたプロパティ配列を作る
List<String> properties = new ArrayList<String>();
Field[] fields = expected.getClass().getDeclaredFields();
for (Field field : fields) {
if (!ArrayUtils.contains(ignoreProperties, field.getName())) {
properties.add(field.getName());
}
}
this.properties = properties.toArray(new String[properties.size()]);
}
}
/**
* Matcherを取得します。
*
* @param expected
* 予想される値
* @param ignoreProperties
* 比較対象外のプロパティ
* @return 一部のプロパティを無視して比較を行えるMatcher
*/
public static <T> Matcher<T> equalsExceptValueOf(T expected, String... ignoreProperties) {
return new BeanIgnorePropertiesMatcher<T>(expected, ignoreProperties);
}
}
SelectPropertiesMatcher.javapackage my.junit.matcher;
import java.util.List;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
interface SelectPropertiesMatcher<T> extends Matcher<T> {
/**
* 予想される値を取得します。
*
* @return 予想される値
*/
T getExpected();
/**
* 実際の値を取得します。
*
* @return 実際の値
*/
Object getActual();
/**
* 一致しなかったプロパティを取得します。
*
* @return 一致しなかったプロパティ
*/
List<String> getUnmatchProperties();
/**
* エラーの場合に表示する、実際の値を示す文字列を追加します。
*
* @param description
* エラー時の文章
*/
public void describeMismatch(Description mismatchDescription);
}
AbstractBeanPropertiesMatcher.javapackage my.junit.matcher;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
/**
* 一部のプロパティを指定してbeanの比較を行えるMatcher
*
* @author blog owner
*
* @param <T>
* 任意のクラス
*/
abstract class AbstractBeanPropertiesMatcher<T> extends TypeSafeMatcher<T>
implements SelectPropertiesMatcher<T> {
/**
* 予想される値
*/
protected T expected = null;
/**
* 実際の値
*/
protected T actual = null;
/**
* 比較対象のプロパティ
*/
protected String[] properties = null;
/**
* 一致しなかったプロパティ
*/
protected List<String> unmatchProperties = new ArrayList<String>();
/**
* コンストラクタ
*/
protected AbstractBeanPropertiesMatcher() {
}
/**
* 比較を行います。
*
* @param actual
* 実際の値
* @return 比較結果
*/
@Override
public boolean matchesSafely(T actual) {
this.actual = actual;
if (expected == actual) {
// 完全に同じもの
return true;
}
if (expected == null || actual == null) {
// 片方だけnullだから違う
return false;
}
// 指定のプロパティを取得しながら比較する
for (String property : properties) {
Object expectedValue = null;
Object actualValue = null;
try {
// 予測した値
expectedValue = FieldUtils.readDeclaredField(expected,
property, true);
// 実際の値
actualValue = FieldUtils.readDeclaredField(actual, property,
true);
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
if (expectedValue == actualValue) {
// 完全に同じもの
continue;
}
if (expectedValue == null || actualValue == null) {
// 片方だけnullだから違う
unmatchProperties.add(property);
continue;
}
if (!expectedValue.equals(actualValue)) {
// 違う値
unmatchProperties.add(property);
continue;
}
}
// 一致しなかったプロパティがない場合はtrue
return unmatchProperties.isEmpty();
}
/**
* エラーの場合に表示する、実際の値を示す文字列を追加します。
*
* @param description
* エラー時の文章
*/
public void describeMismatch(Description mismatchDescription) {
describeMismatchSafely(actual, mismatchDescription);
}
/**
* エラーの場合に表示する、実際の値を示す文字列を追加します。
*
* @param actual
* 実際の値
* @param description
* エラー時の文章
*/
@Override
public void describeMismatchSafely(T actual, Description mismatchDescription) {
setUpDescription(mismatchDescription, actual, unmatchProperties);
}
/**
* エラーの場合に表示する、予測の値を示す文字列を追加します。
*
* @param description
* エラー時の文章
*/
@Override
public void describeTo(Description description) {
setUpDescription(description, expected, unmatchProperties);
}
/**
* エラーの詳細を設定します。
*
* @param description
* 設定先
* @param bean
* 対象のbean
* @param properties
* 対象のプロパティ名リスト
*/
private void setUpDescription(Description description, Object bean,
List<String> properties) {
if (bean == null) {
description.appendValue(null);
return;
}
if (properties.isEmpty()) {
description.appendValue(bean.getClass().getName());
return;
}
int i = -1;
for (String property : properties) {
i++;
if (i != 0) {
description.appendText(", ");
}
description.appendText(property + "=");
try {
description.appendValue(FieldUtils.readDeclaredField(bean,
property, true));
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
}
}
return;
}
/**
* 予想される値を取得します。
*
* @return 予想される値
*/
public T getExpected() {
return expected;
}
/**
* 実際の値を取得します。
*
* @return 実際の値
*/
public Object getActual() {
return actual;
}
/**
* 一致しなかったプロパティを取得します。
*
* @return 一致しなかったプロパティ
*/
public List<String> getUnmatchProperties() {
return unmatchProperties;
}
}
0 件のコメント:
コメントを投稿