Springテストフレームワークを使用して、Hibernateセッションのsave()メソッドをテストしたいと思います。 @Testメソッドは次のとおりです。
@Test
@Transactional
public void testSave() {
User expected = createUser();
getGenericDao().currentSession().save(expected);
User actual = getUser(generatedId);
assertUsersEqual(expected,actual);
}
ユーザーをデータベースにフラッシュしたい。このメソッドの後でユーザーをデータベースに入れたい
getGenericDao().currentSession().save(expected);
次に、Springデータフレームワークを使用してデータベースに移動し、この保存されたユーザーを次の行でフェッチします。
User actual = getUser(generatedId);
私は次のような休止状態のフラッシュ方法を使用しようとしました:
currentSession().setFlushMode(MANUAL);
//do saving here
currentSession().flush();
ユーザーをデータベースにフラッシュしません!ただし、@ Transactionalスプリングアノテーションを使用せず、ユーザーをプログラマティックスプリングトランザクションに保存すると、希望どおりの結果が得られます。残念なことに、春に@Transactionalがないため、dbに保存されたユーザーはロールバックされません。したがって、私のテストメソッドは、後続のテストメソッドのdbと動作を変更します。
したがって、ユーザーをテストメソッド内で(最後ではなく)dbにフラッシュし、テストメソッドの最後ですべての変更をdbにロールバックする必要があります。
[〜#〜] update [〜#〜]次のようにメソッドを準備するための提案:
@Transactional
public void doSave(User user){
getGenericDao().currentSession().save(user);
}
そして、testSave内でdoSaveを呼び出しても何も起こりません。このメソッドを実行した後も、dbにユーザーがいません。ブレークポイントを設定し、コマンドラインからデータベースをチェックします。
[〜#〜] update [〜#〜]返信ありがとうございます。問題は、メソッドflush()がユーザーをデータベースに入れないことです。Isolation.READ_UNCOMMITTEDを試してみましたが、ユーザーがデータベースに入れられません。 @TestメソッドでSpringトランザクションをオフにして、プログラムによるトランザクションで保存を行った場合にのみ、希望どおりの結果を得ることができます。ただし、@ Testメソッドはロールバックされず、保存されたユーザーは後続の@Testメソッドに残されます。ここでは、ユーザーを保存する@Testメソッドは、ロールバックされないため、ユーザーを削除する@Testメソッドほど危険ではありません。そのため、@ Testメソッドのトランザクションサポートが必要です。これにより、ユーザー(または削除)をdbに入れることができなくなります。実際には、@ Testメソッドが終了し、@ Testメソッドのトランザクションがコミットされた後にのみ、ユーザーがデータベースに配置(または削除)されます。 ユーザーを@Testメソッドの途中でdbに保存し、@ Testメソッドの最後でロールバックしたい
ありがとうございました!
最後に、私は次の解決策にこだわりました:
まず、私の_@Test
_メソッドが春の_@Transactional
_サポート内で実行されていません。それがどれほど危険であるかを知るために この記事 を参照してください。次に、_@Repository
_メソッド内で_@Test
_ Beanを使用する代わりに、_@Service
_アノテーションを使用する_@Transactional
_ Beanを自動配線します。奇跡は、このような_@Test
_メソッドです
_@Test
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void testSave() {
Answer created = createAnswer();
Long generatedId = answerService.save(created);
//at this moment answer is already in db
Answer actual=getAnswerById(generatedId);
... }
_
answerオブジェクトをデータベースに入れ(answerService.save(created);
の直後)、メソッドgetAnswerById
がDBに移動して抽出し、保存が正しいかどうかを確認します。
_@Test
_メソッドでデータベースに加えられた変更を削除するには、_JdbcTestUtils.executeSqlScript
_でデータベースを再作成します
@Transactional
_テストに関する警告付き( 春の落とし穴:トランザクションテストは有害と見なされます )。 _@org.springframework.test.context.jdbc.Sql
_を使用して、サービステストでDBを再設定し、_@Transactional
_をコントローラーに使用しました。ConstraintViolationException
は、トランザクションがコミットされたときにのみスローされました。だから私は3つのオプションを見つけました:@Commit
_または@Transactional(propagation = Propagation.NEVER)
を使用してテストに注釈を付けます。 DBの変更に注意してください。TestTransaction
を使用するコード:
_ TestTransaction.flagForCommit();
TestTransaction.end();
_
TransactionTemplate
を使用するコード:
_ @Autowired
private PlatformTransactionManager platformTransactionManager;
@Test(expected = Exception.class)
public void testUpdate() throws Exception {
TransactionTemplate transactionTemplate = new TransactionTemplate(platformTransactionManager);
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
String json = ...
transactionTemplate.execute(ts -> {
try {
mockMvc.perform(put(REST_URL + USER_ID)
.contentType(MediaType.APPLICATION_JSON)
.content(json))
.andExpect(status().isOk());
...
} catch (Exception e) {
e.printStackTrace();
}
return null;
});
_
flush
が機能しない場合は、データベースの分離レベルに大きく依存します。
Isolation
は、データベースのACID
プロパティの1つであり、1つの操作によって加えられた変更が他の同時操作に対してどのように/いつ可視になるかを定義します。
分離レベルはRead Committed
またはRepeatable Read
に設定されていると思います。
また、インポートされたパッケージにも注意する必要があります。
import javax.transaction.Transactional;
の代わりに
import org.springframework.transaction.annotation.Transactional;