DB Tester仕様 - サービスプロバイダーインターフェース(SPI)
SPI概要
本フレームワークはモジュール間の疎結合のためにJava ServiceLoaderを使用します:
設計原則
- API独立性: テストフレームワークモジュールは
db-tester-apiのみに依存 - ランタイム検出: Core実装はServiceLoader経由で読み込み
- 拡張性: カスタム実装でデフォルトを置換可能
APIモジュールSPI
DataSetLoaderProvider
デフォルトのDataSetLoader実装を提供します。
パッケージ: io.github.seijikohara.dbtester.api.spi.DataSetLoaderProvider
インターフェース:
public interface DataSetLoaderProvider {
DataSetLoader getLoader();
}デフォルト実装: db-tester-coreのDefaultDataSetLoaderProvider
使用方法: ローダーを取得するためにConfiguration.defaults()から呼び出される
OperationProvider
テーブルセットに対するデータベース操作を実行します。
パッケージ: io.github.seijikohara.dbtester.api.spi.OperationProvider
インターフェース:
public interface OperationProvider {
void execute(
Operation operation,
TableSet tableSet,
DataSource dataSource,
TableOrderingStrategy tableOrderingStrategy,
TransactionMode transactionMode,
@Nullable Duration queryTimeout);
}デフォルト実装: db-tester-coreのDefaultOperationProvider
パラメータ:
| パラメータ | 型 | 説明 |
|---|---|---|
operation | Operation | 実行するデータベース操作 |
tableSet | TableSet | テーブルと行を含むテーブルセット |
dataSource | DataSource | コネクション用のJDBCデータソース |
tableOrderingStrategy | TableOrderingStrategy | テーブル処理順序の戦略 |
transactionMode | TransactionMode | トランザクション動作モード |
queryTimeout | @Nullable Duration | クエリタイムアウト、またはタイムアウトなしの場合はnull |
操作:
NONE- 操作なしINSERT- 行を挿入UPDATE- 主キーで更新DELETE- 主キーで削除DELETE_ALL- 全行を削除UPSERT- Upsert(挿入または更新)TRUNCATE_TABLE- テーブルを切り捨てCLEAN_INSERT- 全削除後に挿入TRUNCATE_INSERT- 切り捨て後に挿入
AssertionProvider
期待値検証のためのデータベースアサーションを実行します。
パッケージ: io.github.seijikohara.dbtester.api.spi.AssertionProvider
インターフェース:
public interface AssertionProvider {
// コア比較メソッド
void assertEquals(TableSet expected, TableSet actual);
void assertEquals(TableSet expected, TableSet actual, AssertionFailureHandler failureHandler);
void assertEquals(Table expected, Table actual);
void assertEquals(Table expected, Table actual, Collection<String> additionalColumnNames);
void assertEquals(Table expected, Table actual, AssertionFailureHandler failureHandler);
// カラム除外付き比較
void assertEqualsIgnoreColumns(TableSet expected, TableSet actual, String tableName,
Collection<String> ignoreColumnNames);
void assertEqualsIgnoreColumns(Table expected, Table actual,
Collection<String> ignoreColumnNames);
// カラム戦略付き比較
void assertEqualsWithStrategies(Table expected, Table actual,
Collection<ColumnStrategyMapping> columnStrategies);
// SQLクエリベース比較
void assertEqualsByQuery(TableSet expected, DataSource dataSource, String tableName,
String sqlQuery, Collection<String> ignoreColumnNames);
void assertEqualsByQuery(Table expected, DataSource dataSource, String tableName,
String sqlQuery, Collection<String> ignoreColumnNames);
}デフォルト実装: db-tester-coreのDefaultAssertionProvider
主要メソッド:
| メソッド | 説明 |
|---|---|
assertEquals(TableSet, TableSet) | 2つのテーブルセットを比較 |
assertEquals(Table, Table) | 2つのテーブルを比較 |
assertEqualsIgnoreColumns(...) | 特定カラムを無視して比較 |
assertEqualsWithStrategies(...) | カラム固有の比較戦略を使用して比較 |
assertEqualsByQuery(...) | クエリ結果を期待データと比較 |
動作:
- 期待値と実際のテーブルセット/テーブルを比較
- カラムごとに比較戦略を適用(STRICT、IGNORE、NUMERICなど)
- すべての差異を収集(フェイルファストではない)
- 不一致時は人間が読みやすい要約 + YAML詳細を出力
出力形式の詳細についてはエラーハンドリング - 検証エラーを参照してください。
ExpectationProvider
期待テーブルセットに対するデータベース状態を検証します。
パッケージ: io.github.seijikohara.dbtester.api.spi.ExpectationProvider
インターフェース:
public interface ExpectationProvider {
// 基本検証
void verifyExpectation(TableSet expectedTableSet, DataSource dataSource);
// カラム除外付き
default void verifyExpectation(TableSet expectedTableSet, DataSource dataSource,
Collection<String> excludeColumns);
// カラム戦略付き
default void verifyExpectation(TableSet expectedTableSet, DataSource dataSource,
Collection<String> excludeColumns,
Map<String, ColumnStrategyMapping> columnStrategies);
// 行順序制御付き
default void verifyExpectation(TableSet expectedTableSet, DataSource dataSource,
Collection<String> excludeColumns,
Map<String, ColumnStrategyMapping> columnStrategies,
RowOrdering rowOrdering);
}デフォルト実装: db-tester-coreのDefaultExpectationProvider
メソッド:
| メソッド | 説明 |
|---|---|
verifyExpectation(TableSet, DataSource) | 基本的なデータベース状態検証 |
verifyExpectation(..., excludeColumns) | 指定カラムを除外して検証 |
verifyExpectation(..., columnStrategies) | カラム比較戦略付きで検証 |
verifyExpectation(..., rowOrdering) | 行順序制御付きで検証 |
パラメータ:
| パラメータ | 型 | 説明 |
|---|---|---|
expectedTableSet | TableSet | 期待テーブルデータを含む期待テーブルセット |
dataSource | DataSource | 実際のデータを取得するためのデータベースコネクションソース |
excludeColumns | Collection<String> | 比較から除外するカラム名(大文字小文字区別なし) |
columnStrategies | Map<String, ColumnStrategyMapping> | カラム名でキーイングされたカラム比較戦略 |
rowOrdering | RowOrdering | 行比較戦略(ORDEREDまたはUNORDERED) |
プロセス:
- 期待テーブルセット内の各テーブルに対して、データベースから実際のデータを取得
- 実際のデータを期待テーブルに存在するカラムのみにフィルタリング
- カラム除外と比較戦略を適用
- フィルタリングされた実際のデータを期待データと比較
- 検証失敗時は
AssertionErrorをスロー
ScenarioNameResolver
テストメソッドコンテキストからシナリオ名を解決します。
パッケージ: io.github.seijikohara.dbtester.api.scenario.ScenarioNameResolver
インターフェース:
public interface ScenarioNameResolver {
int DEFAULT_PRIORITY = 0;
ScenarioName resolve(Method testMethod);
default boolean canResolve(Method testMethod) {
return true;
}
default int priority() {
return DEFAULT_PRIORITY;
}
}メソッド:
| メソッド | 戻り値型 | デフォルト | 説明 |
|---|---|---|---|
resolve(Method) | ScenarioName | - | テストメソッドからシナリオ名を解決 |
canResolve(Method) | boolean | true | リゾルバがメソッドを処理できるかを返す |
priority() | int | 0 | リゾルバ選択の優先度を返す(大きいほど優先) |
実装:
| 実装 | モジュール | 説明 |
|---|---|---|
JUnitScenarioNameResolver | db-tester-junit | JUnitメソッド名から解決 |
SpockScenarioNameResolver | db-tester-spock | Spockフィーチャー名から解決 |
KotestScenarioNameResolver | db-tester-kotest | Kotestテストケース名から解決 |
解決ロジック:
- 登録されたすべてのリゾルバを
priority()で降順ソート - 各リゾルバに
canResolve()を問い合わせ trueを返す最初のリゾルバを使用resolve()を呼び出してシナリオ名を取得
CoreモジュールSPI
FormatProvider
特定形式のデータセットファイルを解析します。
パッケージ: io.github.seijikohara.dbtester.internal.format.spi.FormatProvider
インターフェース:
public interface FormatProvider {
FileExtension supportedFileExtension();
DataSet parse(Path directory);
}メソッド:
| メソッド | 戻り値型 | 説明 |
|---|---|---|
supportedFileExtension() | FileExtension | 先頭ドットなしのファイル拡張子を返す(例: "csv") |
parse(Path) | TableSet | ディレクトリ内のすべてのファイルをTableSetに解析 |
実装:
| 実装 | 拡張子 | 区切り文字 |
|---|---|---|
CsvFormatProvider | .csv | カンマ |
TsvFormatProvider | .tsv | タブ |
注意: FormatProviderは内部SPIであり、外部実装をサポートしていません。
ServiceLoader登録
META-INF/servicesファイル
db-tester-core:
# META-INF/services/io.github.seijikohara.dbtester.api.spi.DataSetLoaderProvider
io.github.seijikohara.dbtester.internal.loader.DefaultDataSetLoaderProvider
# META-INF/services/io.github.seijikohara.dbtester.api.spi.OperationProvider
io.github.seijikohara.dbtester.internal.spi.DefaultOperationProvider
# META-INF/services/io.github.seijikohara.dbtester.api.spi.AssertionProvider
io.github.seijikohara.dbtester.internal.spi.DefaultAssertionProvider
# META-INF/services/io.github.seijikohara.dbtester.api.spi.ExpectationProvider
io.github.seijikohara.dbtester.internal.spi.DefaultExpectationProvider
# META-INF/services/io.github.seijikohara.dbtester.internal.format.spi.FormatProvider
io.github.seijikohara.dbtester.internal.format.csv.CsvFormatProvider
io.github.seijikohara.dbtester.internal.format.tsv.TsvFormatProviderdb-tester-junit:
# META-INF/services/io.github.seijikohara.dbtester.api.scenario.ScenarioNameResolver
io.github.seijikohara.dbtester.junit.jupiter.spi.JUnitScenarioNameResolverdb-tester-spock:
# META-INF/services/io.github.seijikohara.dbtester.api.scenario.ScenarioNameResolver
io.github.seijikohara.dbtester.spock.spi.SpockScenarioNameResolverdb-tester-kotest:
# META-INF/services/io.github.seijikohara.dbtester.api.scenario.ScenarioNameResolver
io.github.seijikohara.dbtester.kotest.spi.KotestScenarioNameResolverJPMSモジュール宣言
db-tester-api module-info.java:
module io.github.seijikohara.dbtester.api {
uses io.github.seijikohara.dbtester.api.spi.DataSetLoaderProvider;
uses io.github.seijikohara.dbtester.api.spi.OperationProvider;
uses io.github.seijikohara.dbtester.api.spi.AssertionProvider;
uses io.github.seijikohara.dbtester.api.spi.ExpectationProvider;
uses io.github.seijikohara.dbtester.api.scenario.ScenarioNameResolver;
}db-tester-core module-info.java:
module io.github.seijikohara.dbtester.core {
provides io.github.seijikohara.dbtester.api.spi.DataSetLoaderProvider
with io.github.seijikohara.dbtester.internal.loader.DefaultDataSetLoaderProvider;
provides io.github.seijikohara.dbtester.api.spi.OperationProvider
with io.github.seijikohara.dbtester.internal.spi.DefaultOperationProvider;
// ... 他のプロバイダー
}カスタム実装
カスタムDataSetLoader
カスタムデータセットローダーを提供するには:
DataSetLoaderインターフェースを実装:
public class CustomDataSetLoader implements DataSetLoader {
@Override
public List<TableSet> loadPreparationDataSets(TestContext context) {
// カスタム読み込みロジック
}
@Override
public List<TableSet> loadExpectationDataSets(TestContext context) {
// カスタム読み込みロジック
}
}Configuration経由で登録:
var config = Configuration.builder()
.loader(new CustomDataSetLoader())
.build();
DatabaseTestExtension.setConfiguration(context, config);カスタムScenarioNameResolver
カスタムシナリオリゾルバを提供するには:
ScenarioNameResolverを実装:
public class CustomScenarioNameResolver implements ScenarioNameResolver {
private static final int HIGH_PRIORITY = 100;
@Override
public ScenarioName resolve(Method testMethod) {
// メソッドからシナリオ名を抽出
}
@Override
public boolean canResolve(Method testMethod) {
// サポートされるメソッドに対してtrueを返す
}
@Override
public int priority() {
return HIGH_PRIORITY; // デフォルトリゾルバより高い優先度
}
}- ServiceLoader経由で登録:
# META-INF/services/io.github.seijikohara.dbtester.api.scenario.ScenarioNameResolver
com.example.CustomScenarioNameResolverカスタムFormatProvider
追加のファイル形式をサポートするには(内部SPI):
FormatProviderを実装:
public class XmlFormatProvider implements FormatProvider {
@Override
public FileExtension supportedFileExtension() {
return new FileExtension("xml");
}
@Override
public TableSet parse(Path directory) {
// ディレクトリ内のすべてのXMLファイルを解析
}
}- ServiceLoader経由で登録:
# META-INF/services/io.github.seijikohara.dbtester.internal.format.spi.FormatProvider
com.example.XmlFormatProviderプロバイダー優先順位
複数のプロバイダーが登録されている場合:
| SPI | 選択方法 |
|---|---|
DataSetLoaderProvider | 最初に見つかったもの |
OperationProvider | 最初に見つかったもの |
AssertionProvider | 最初に見つかったもの |
ExpectationProvider | 最初に見つかったもの |
ScenarioNameResolver | priority()でソート、canResolve()がtrueを返す最初のもの |
FormatProvider | 一致するsupportedFileExtension()を持つ最初のもの |
関連仕様
- 概要 - フレームワークの目的と主要概念
- アーキテクチャ - モジュール構造
- 設定 - 設定クラス
- テストフレームワーク - フレームワーク統合