Spring TestContextフレームワークのプログラムによるトランザクション

Spring TestContextフレームワークのプログラムトランザクション

1. 前書き

Springは、application code全体およびintegration testsでの宣言型トランザクション管理を優れた方法でサポートしています。

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

この記事では、how to programmatically interact with automatic transactions set up by Spring in transactional testsを確認します。

2. 前提条件

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

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

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

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

このようなテストでは、every test method is wrapped in a transaction, which gets rolled back when the method exits

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

3. TestTransactionクラス

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

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

各メソッドは、テストメソッドの実行中に存在する唯一の現在のトランザクションと対話します。

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());
}

これらのメソッドは、名前が示すとおり、単にトランザクションにフラグを立てることに注意してください。 つまり、the transaction isn’t committed or rolled back immediately, but only just before it ends.

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は、@Transactionalの注釈が付けられたテストでSpringsが自動的に構成するリスナーです。

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

はい、このコードは重層的で抽象的です。 これは、多くの場合、Springフレームワークの中核部分です。

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

5. 結論

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

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