All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nablarch.test.Assertion Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
package nablarch.test;

import nablarch.core.dataformat.DataRecord;
import nablarch.core.db.statement.SqlResultSet;
import nablarch.core.db.statement.SqlRow;
import nablarch.core.util.ObjectUtil;
import nablarch.core.util.StringUtil;
import nablarch.core.util.annotation.Published;

import nablarch.test.core.db.TableData;
import nablarch.test.core.util.ByteArrayAwareMap;
import nablarch.test.core.util.MapCollector;
import org.junit.Assert;
import org.junit.ComparisonFailure;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import static nablarch.core.util.Builder.concat;


/**
 * 表明クラス。
* テスト実行結果が期待通りであることを確認するのに使用する。 * * @author Tsuyoshi Kawasaki * @author Koichi Asano */ @Published public final class Assertion { /** * 複数のTableDataの比較を行う。
* 期待値として与えられたTableDataと、それに対応するテーブルの状態が等しいことを表明する。 * * @param expectedTables 期待値 */ public static void assertTableEquals(List expectedTables) { assertTableEquals("", expectedTables); } /** * 複数のTableDataの比較を行う。
* 期待値として与えられたTableDataと、それに対応するテーブルの状態が等しいことを表明する。 * * @param message 比較失敗時のメッセージ * @param expectedTables 期待値 */ public static void assertTableEquals(String message, List expectedTables) { for (TableData expected : expectedTables) { assertTableEquals(message, expected); } } /** * TableDataの比較を行う。
* 期待値として与えられたTableDataと、それに対応するテーブルの状態が等しいことを表明する。 * * @param expected 期待値 */ public static void assertTableEquals(TableData expected) { assertTableEquals("", expected); } /** * TableDataの比較を行う。
* 期待値として与えられたTableDataと、それに対応するテーブルの状態が等しいことを表明する。 * * @param message 比較失敗時のメッセージ * @param expected 期待値 */ public static void assertTableEquals(String message, TableData expected) { TableData actual = expected.getClone(); actual.loadData(); assertTableEquals(message, expected, actual); } /** * TableDataの比較を行う。
* 引数で与えられたtableDataが等価であることを表明する。 * * @param expected 期待する値 * @param actual 実際の値 */ public static void assertTableEquals(TableData expected, TableData actual) { assertTableEquals("", expected, actual); } /** * SqlResultSetの比較を行う。
* 引数で与えられたSqlResultSetが等価であることを表明する。 * * @param expected 期待する値 * @param actual 実際の値 */ public static void assertSqlResultSetEquals(List> expected, SqlResultSet actual) { assertSqlResultSetEquals("", expected, actual); } /** * SqlResultSetの比較を行う。
* 引数で与えられたSqlResultSetが等価であることを表明する。 * * @param message メッセージ * @param expected 期待する値 * @param actual 実際の値 */ public static void assertSqlResultSetEquals(String message, List> expected, SqlResultSet actual) { assertListMapEquals(message, expected, actual); } /** * {@literal List}の比較を行う。
* * @param expected 期待する値 * @param actual 実際の値 * @see #assertListMapEquals(String, List, List) */ public static void assertListMapEquals(List> expected, List> actual) { assertListMapEquals("", expected, actual); } /** * {@literal List}の比較を行う。
* 引数で与えられた{@literal List}が等価であることを表明する。 * 実際の値のMapのvalueは文字列に変換されて比較される。 * * @param message メッセージ * @param expected 期待する値 * @param actual 実際の値 */ public static void assertListMapEquals(String message, List> expected, List> actual) { if (expected == null && actual == null) { return; } // 片方だけnullでないこと assertNotXorNull(message, expected, actual); // サイズが異なれば等価でない if (expected.size() != actual.size()) { failComparing(message + " size differs. expected size=[" + expected.size() + "], actual size=[" + actual.size() + "]", expected, actual); } for (int rowNum = 0; rowNum < expected.size(); rowNum++) { assertMapEquals(message + " line no=[" + (rowNum + 1) + "]", expected.get(rowNum), actual.get(rowNum)); } } /** * SqlRowの比較を行う。
* 引数で与えられたSqlResultSetが等価であることを表明する。
* なお、バイナリカラムが含まれている場合は、比較できない。 * * @param expected 期待する値 * @param actual 実際の値 */ public static void assertSqlRowEquals(Map expected, SqlRow actual) { assertSqlRowEquals("", expected, actual); } /** * SqlRowの比較を行う。
* 引数で与えられたSqlResultSetが等価であることを表明する。
* なお、バイナリカラムが含まれている場合は、比較できない。 * * @param message メッセージ * @param expected 期待する値 * @param actual 実際の値 */ public static void assertSqlRowEquals(String message, Map expected, SqlRow actual) { assertMapEquals(message, expected, actual); } /** * Mapの比較を行う。
* * @param expected 期待する値 * @param actual 実際の値 * @see #assertMapEquals(String, Map, Map) */ public static void assertMapEquals(Map expected, Map actual) { assertMapEquals("", expected, actual); } /** * Mapの比較を行う。
* 引数で与えられたSqlResultSetが等価であることを表明する。 * 実際の値のMapのvalueは文字列に変換されて比較される。 * * @param message 比較失敗時のメッセージ * @param expected 期待する値 * @param actual 実際の値 */ public static void assertMapEquals(String message, Map expected, Map actual) { if (expected == null && actual == null) { return; } // 片方だけnullでないこと assertNotXorNull(message, expected, actual); // 文字列に寄せて比較する。 Map actualAsString = copyValuesAsString(actual); if (!actualAsString.equals(expected)) { // 目視による結果確認を容易にするためTreeMapを使用 expected = new TreeMap(expected); failComparing(message, expected, actualAsString); } } /** * 格納された値を文字列に変換してコピーを行う。 * * @param orig 元のオブジェクト * @return 変換後のオブジェクト */ private static Map copyValuesAsString(Map orig) { @SuppressWarnings("unchecked") Map o = (Map) orig; // 目視による結果確認を容易にするためTreeMapを使用 return (new MapCollector(new TreeMap()) { protected String evaluate(String key, Object value) { return value == null ? null : StringUtil.toString(value); } }).collect(o); } /** * TableDataの比較を行う。
* 引数で与えられたtableDataが等価であることを表明する。 * * @param message 失敗時のメッセージ * @param expected 期待する値 * @param actual 実際の値 */ public static void assertTableEquals(String message, TableData expected, TableData actual) { if (expected == actual) { return; } assertNotXorNull(message, expected, actual); String[] primaryKeys = expected.getPrimaryKeys(); String[] columns = expected.getColumnNames(); // DBにあってExcelにないデータをチェックするための配列 boolean[] dbDataFound = createArray(actual.size(), false); // 主キーが同じであるレコードを探す。 // 発見した場合は、その他のカラムが等価であるか確認する for (int expIdx = 0; expIdx < expected.size(); expIdx++) { // 主キーが同じレコードを示すインデックス int samePkIdx = -1; pkMatching: for (int actIdx = 0; actIdx < actual.size(); actIdx++) { // 全ての主キーがマッチするか for (String primaryKey : primaryKeys) { final Object expPk = expected.getValue(expIdx, primaryKey); final Object actPk = actual.getValue(actIdx, primaryKey); final String expPkStr = expPk == null ? "null" : StringUtil.toString(expPk); final String actPkStr = actPk == null ? "null" : StringUtil.toString(actPk); if (!expPkStr.equals(actPkStr)) { continue pkMatching; // 次のレコードへ } } // 全ての主キーが同じデータを発見 samePkIdx = actIdx; // ExcelにあったDBデータの消しこみ dbDataFound[samePkIdx] = true; break; } // 主キーがマッチするレコードが見つからない if (samePkIdx == -1) { fail(message, " the table of [", expected.getTableName(), "] is expected to have a record whose PK is [", expected.getPkValues(expIdx), "], but there is no such record in the table.", " row number=[", expIdx + 1, "]"); } // 1カラムづつ比較 for (String column : columns) { Object expData = expected.getValue(expIdx, column); Object actData = actual.getValue(samePkIdx, column); String msg = concat(message, " table=", expected.getTableName(), " line=", (expIdx + 1), " column=", column); assertEqualsAsString(msg, expData, actData); // 文字列として比較 } } // DBにあってExcelになかったデータのチェック for (int i = 0; i < dbDataFound.length; i++) { boolean found = dbDataFound[i]; if (!found) { fail(message, " an unexpected record is included in the table of [", actual.getTableName(), "].", " PK=[", actual.getPkValues(i), "]"); } } } /** * 配列を作成する。 * * @param size サイズ * @param initialValue 初期値 * @return 配列 */ private static boolean[] createArray(int size, boolean initialValue) { boolean[] array = new boolean[size]; for (int i = 0; i < size; i++) { array[i] = initialValue; } return array; } /** * 要素の順序を考慮しないで、2つの配列が等価な要素を保持していることを表明する。
* * @param 配列の総称型 * @param message メッセージ * @param expected 期待する値 * @param actual 実際の値 */ public static void assertEqualsIgnoringOrder(String message, T[] expected, T[] actual) { assertEqualsIgnoringOrder(message, Arrays.asList(expected), Arrays.asList(actual)); } /** * 要素の順序を考慮しないで、2つの配列が等価な要素を保持していることを表明する。
* * @param 配列の総称型 * @param expected 期待する値 * @param actual 実際の値 */ public static void assertEqualsIgnoringOrder(T[] expected, T[] actual) { assertEqualsIgnoringOrder("", expected, actual); } /** * 要素の順序を考慮しないで、2つのコレクションが等価な要素を保持していることを表明する。
* * @param コレクションの総称型 * @param expected 期待する値 * @param actual 実際の値 */ public static void assertEqualsIgnoringOrder(Collection expected, Collection actual) { assertEqualsIgnoringOrder("", expected, actual); } /** * 要素の順序を考慮しないで、2つのコレクションが等価な要素を保持していることを表明する。
* * @param コレクションの総称型 * @param message メッセージ * @param expected 期待する値 * @param actual 実際の値 */ public static void assertEqualsIgnoringOrder(String message, Collection expected, Collection actual) { new AssertionIgnoringOrder(message, expected, actual).doAssert(); } /** * 要素の順序を考慮しないで、2つのコレクションが等価な要素を保持していることを表明する。
* 等価かであるかどうかは、比較対象要素の文字列表現が等しいかどうかで判定する。 * * @param message メッセージ * @param expected 期待する値 * @param actual 実際の値 * @param 期待する値の型 * @param 実際の値の型 */ @SuppressWarnings("unchecked") public static void assertEqualsIgnoringOrder(String message, List> expected, List> actual) { List> e = (List>) expected; List> a = (List>) actual; new AssertionIgnoringOrder, Map>(message, e, a) .doAssert(new AsString()); } /** * 要素の順序を考慮しないで、2つのコレクションが等価な要素を保持していることを表明するクラス。
* * @param 期待値の要素の型 * @param
実際の値の要素の型 * @author Tsuyoshi Kawasaki */ private static final class AssertionIgnoringOrder { /** 比較失敗時のメッセージ */ private String message; /** 期待する値 */ private Collection expectedOriginal; /** 実際の値 */ private Collection actualOriginal; /** * コンストラクタ * * @param message 比較失敗時のメッセージ * @param expected 期待する値 * @param actual 実際の値 */ private AssertionIgnoringOrder(String message, Collection expected, Collection actual) { this.message = message; this.expectedOriginal = expected; this.actualOriginal = actual; } /** * 等価判定クラスを用いてアサートする。 * @param comparator 比較用クラス等価判定クラス */ void doAssert(EquivCondition comparator) { if (expectedOriginal == actualOriginal) { return; // 等値であれば等価 } assertNotXorNull(message, expectedOriginal, actualOriginal); // 元の値を破壊しないようコピーを作成して比較 doAssertEqualsIgnoringOrder(new LinkedList(expectedOriginal), new LinkedList(actualOriginal), comparator); } /** アサートを実行する。 */ void doAssert() { doAssert(new EquivCondition() { /** {@inheritDoc} */ public boolean isEquivalent(E expected, A actual) { return expected.equals(actual); } }); } /** * 要素の順序を考慮しないで、2つの連結リストが等価な要素を保持していることを表明する。
* 引数で与えられたリストの内容は保証されない(破壊的メソッド)。 * * @param expected 期待する値 * @param actual 実際の値 * @param eq 比較ロジック */ private void doAssertEqualsIgnoringOrder(LinkedList expected, LinkedList
actual, EquivCondition eq) { // サイズが異なれば、順番に関係なく等価でない if (expected.size() != actual.size()) { failComparing(message, expected, actual); } // 両方空であれば等価(最終的な終了条件、 前段でサイズチェック済みなのでexpectedのみ) if (expected.isEmpty()) { return; } // 等価な値を探索 for (E e : expected) { for (A a : actual) { if (eq.isEquivalent(e, a)) { // 等価な値を発見したら、その要素を取り除き再帰呼び出し expected.remove(e); actual.remove(a); doAssertEqualsIgnoringOrder(expected, actual, eq); return; // 全ての要素が等価 } // この時点で等価でないことが判明しているが、可能な限り比較を行う(行番号表示ができないため)。 } } // 等価でなかった要素を表示する。 failComparing( message + " different element(s) found. expected has " + expected + ", actual has " + actual + ". " , expectedOriginal, actualOriginal); } // failがあるので到達しない。 } /** * 等価の判定を行うインタフェース。 * * @param 期待値の型 * @param 実際の値の型 */ static interface EquivCondition { /** * 等価であるか判定する。 * @param expected 期待値 * @param actual 実際の値 * @return 等価である場合、真 */ boolean isEquivalent(E expected, A actual); } /** * Mapが文字列として等価であるか判定する{@link EquivCondition}実装クラス。 * * @param 期待値のvalueの型 * @param 実際の値のvalueの型 */ static class AsString implements EquivCondition, Map> { /** {@inheritDoc} */ public boolean isEquivalent(Map expected, Map actual) { Map sortedExpected = wrap(expected); Map sortedActual = wrap(actual); return sortedExpected.toString().equals(sortedActual.toString()); } } /** * 文字列として比較した場合に等価であることを表明する。 * * @param message メッセージ * @param expected 期待する値 * @param actual 実際の値 */ public static void assertEqualsAsString(String message, Object expected, Object actual) { final String expectedStr = expected == null ? "null" : StringUtil.toString(expected); final String actualStr = actual == null ? "null" : StringUtil.toString(actual); Assert.assertEquals(message, expectedStr, actualStr); } /** * 比較に失敗したことを通知する。
* * @param message メッセージ * @param expected 期待する値 * @param actual 実際の値 */ public static void failComparing(String message, Object expected, Object actual) { final String expectedStr = expected == null ? "null" : StringUtil.toString(expected); final String actualStr = actual == null ? "null" : StringUtil.toString(actual); throw new ComparisonFailure(message, expectedStr, actualStr); } /** * 片方だけnullでないことを表明する。 * * @param message メッセージ * @param expected 期待する値 * @param actual 実際の値 */ public static void assertNotXorNull(String message, Object expected, Object actual) { // 片方だけnullならば比較失敗とする。 if (expected != null && actual == null || expected == null && actual != null) { failComparing(message, expected, actual); } } /** * 失敗を表明する。引数で与えられたメッセージを連結して一つのメッセージとする。 * * @param messages メッセージ */ public static void fail(Object... messages) { Assert.fail(concat(messages)); } /** * Object に設定されたプロパティを表明する。
*

* expected に指定した Map の持つキーに対して、 actual のプロパティの値を全てチェックする。
* actual のプロパティが文字列ではない場合、プロパティの値を{@link StringUtil#toString(Object)}で比較する。 *

* * @param expected オブジェクトが持つプロパティに期待される値を設定した Map * @param actual 実際の値 */ public static void assertProperties(Map expected, Object actual) { assertProperties("", expected, actual); } /** * Object に設定されたプロパティを表明する。
*

* expected に指定した Map の持つキーに対して、 actual のプロパティの値を全てチェックする。
* actual のプロパティが文字列ではない場合、プロパティの値を{@link StringUtil#toString(Object)}で比較する。 *

* * @param message メッセージ * @param expected オブジェクトが持つプロパティに期待される値を設定した Map * @param actual 実際の値 */ public static void assertProperties(String message, Map expected, Object actual) { String actualClassName = actual.getClass().getName(); Map actualMap = new TreeMap(); for (String key : expected.keySet()) { Object actualValue = null; try { actualValue = ObjectUtil.getProperty(actual, key); } catch (RuntimeException e) { // 取得失敗 fail(message, actualClassName, " does not have property ", key); } actualMap.put(key, actualValue == null ? null : StringUtil.toString(actualValue)); } Map expectedMap = new TreeMap(expected); // 結果を見やすくするために、toStringした結果を比較 message += "; class property assertion failed ; target class name = " + actualClassName; assertEqualsAsString(message, expectedMap, actualMap); } /** * {@link DataRecord}の比較を行う。 * * @param msg 比較失敗時のメッセージ * @param expected 期待値 * @param actual 実際の値 */ public static void assertEquals(String msg, List expected, List actual) { assertNotXorNull(msg, expected, actual); assertEqualsAsString(msg, wrap(expected), wrap(actual)); } /** * {@link DataRecord}の比較を行う。 * * @param msg 比較失敗時のメッセージ * @param expected 期待値 * @param actual 実際の値 */ public static void assertEquals(String msg, DataRecord expected, DataRecord actual) { assertNotXorNull(msg, expected, actual); Map exp = wrap(expected); Map act = wrap(actual); assertEqualsAsString(msg, exp, act); } /** * データレコードを比較用にラップする。 * * @param dataRecords 比較対象のデータレコード * @return ラップしたデータレコード */ private static List> wrap(List> dataRecords) { List> wrapped = new ArrayList>(dataRecords.size()); for (Map e : dataRecords) { wrapped.add(wrap(e)); } return wrapped; } /** * データレコードを比較用にラップする。
* * @param dataRecord 比較対象のデータレコード * @return ラップしたデータレコード */ private static Map wrap(Map dataRecord) { // バイト列を扱えるようにする return new ByteArrayAwareMap( new TreeMap(dataRecord) // 比較しやすいようTreeMapを使用 ); } /** * 期待値と実際の値が等価であることを表明する。
* 等価でなかった場合は、デバッグを容易にするため * AssertionErrorではなくComparisonFailureをスローする。 * * @param msg 比較失敗時のメッセージ * @param expected 期待値 * @param actual 実際の値 * @throws ComparisonFailure 等価でなかった場合 */ public static void assertEquals(String msg, Object expected, Object actual) throws ComparisonFailure { if (expected == actual) { return; } assertNotXorNull(msg, expected, actual); if (!expected.equals(actual)) { failComparing(msg, expected, actual); } } /** * プライベートコンストラクタ
* 本クラスはインスタンス化できない。 */ private Assertion() { } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy