1. 序章

Springは、アプリケーションコード全体および統合テストでの宣言型トランザクション管理を優れた方法でサポートしています。

ただし、トランザクションの境界をきめ細かく制御する必要がある場合があります。

この記事では、トランザクションテストでSpringによって設定された自動トランザクションとプログラムで対話する方法を説明します。

2. 前提条件

Springアプリケーションにいくつかの統合テストがあると仮定しましょう。

具体的には、データベースと相互作用するテストを検討しています。たとえば、永続層が正しく動作していることを確認します。

トランザクションとして注釈が付けられた標準のテストクラスについて考えてみましょう。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { HibernateConf.class })
@Transactional
public class HibernateBootstrapIntegrationTest { ... }

このようなテストでは、すべてのテストメソッドがトランザクションにラップされ、メソッドが終了するとロールバックされます。

もちろん、特定のメソッドにのみ注釈を付けることも可能です。 この記事で説明することはすべて、そのシナリオにも当てはまります。

3. TestTransactionクラス

この記事の残りの部分では、org.springframework.test.context.transaction.TestTransactionという単一のクラスについて説明します。

これは、テストでトランザクションを操作するために使用できるいくつかの静的メソッドを持つユーティリティクラスです。

各メソッドは、テストメソッドの実行中に実行されている唯一の現在のトランザクションと相互作用します。

3.1. 現在のトランザクションの状態を確認する

テストでよく行うことの1つは、物事が想定された状態にあることを確認することです。

したがって、現在アクティブなトランザクションがあるかどうかを確認する必要があります。

assertTrue(TestTransaction.isActive());

または、現在のトランザクションにロールバックのフラグが設定されているかどうかを確認することもできます。

assertTrue(TestTransaction.isFlaggedForRollback());

そうである場合、Springは、自動的にまたはプログラムで、終了する直前にロールバックします。 それ以外の場合は、閉じる直前にコミットします。

3.2. コミットまたはロールバックのトランザクションにフラグを立てる

トランザクションを閉じる前に、トランザクションをコミットまたはロールバックするポリシーをプログラムで変更できます。

TestTransaction.flagForCommit();
TestTransaction.flagForRollback();

通常、テストのトランザクションは、開始時にロールバックのフラグが立てられます。 ただし、メソッドに @Commit アノテーションがある場合は、代わりにコミットのフラグが立てられ始めます。

@Test
@Commit
public void testFlagForCommit() {
    assertFalse(TestTransaction.isFlaggedForRollback());
}

これらのメソッドは、名前が示すように、単にトランザクションにフラグを立てるだけであることに注意してください。 つまり、トランザクションはすぐにコミットまたはロールバックされるのではなく、終了する直前にのみコミットされます。

3.3. トランザクションの開始と終了

トランザクションをコミットまたはロールバックするには、メソッドを終了させるか、明示的に終了します。

TestTransaction.end();

後でデータベースと再度対話する場合は、新しいトランザクションを開始する必要があります。

TestTransaction.start();

メソッドのデフォルトに従って、新しいトランザクションにロールバック(またはコミット)のフラグが立てられることに注意してください。 つまり、flagFor…への以前の呼び出しは新しいトランザクションに影響を与えません。

4. いくつかの実装の詳細

TestTransactionは魔法のようなものではありません。 次に、Springを使用したテストでのトランザクションについてもう少し学ぶために、その実装を見ていきます。

そのいくつかのメソッドは、単に現在のトランザクションにアクセスし、その機能の一部をカプセル化するだけであることがわかります。

4.1. TestTransaction はどこから現在のトランザクションを取得しますか?

コードに直接行きましょう:

TransactionContext transactionContext
  = TransactionContextHolder.getCurrentTransactionContext();

TransactionContextHolder は、TransactionContextを保持するThreadLocalの単なる静的ラッパーです。

4.2. スレッドローカルコンテキストを設定するのは誰ですか?

setCurrentTransactionContext メソッドを呼び出す人を見ると、呼び出し元はTransactionalTestExecutionListener.beforeTestMethodだけであることがわかります。

TransactionalTestExecutionListener は、Springsが@Transactionalと注釈されたテストで自動的に構成するリスナーです。

TransactionContext は、実際のトランザクションへの参照を保持していないことに注意してください。 代わりに、PlatformTransactionManagerのファサードにすぎません。

はい、このコードは非常に階層化されており、抽象的です。 多くの場合、これはSpringフレームワークのコア部分です。

複雑さの下で、Springが黒魔術を行わない方法を見るのは興味深いことです。必要な簿記、配管、例外処理などがたくさんあるだけです。

5. 結論

このクイックチュートリアルでは、Springベースのテストでトランザクションをプログラムで操作する方法を見てきました。

これらすべての例の実装は、 GitHubプロジェクトにあります。これはMavenプロジェクトであるため、そのままインポートして実行するのは簡単です。