インテグレーションテストを書いていてハマったこと
概要
SpringBootでJUnitを使い、インテーグレーションテストを書いていた時にハマったこととその解決方法を書きます。
状況
1.Controllerへリクエストを投げると各テーブルに正しくデータが登録されることを確認したいテストを作成していた。
2.テスト実施でDBに不要なレコードが追加されないようにテストクラスに@Transactionalをつけている
3.事前に特定の情報が各テーブルに登録されていないと実施できないテスト(これもロールバックできるように2と同じトランザクション内で行う)
起こったこと
あれ?なんかエンティティが思うように取得できない?なぜにnull?テストじゃなければ動いているのになー
以下のようなエンティティを使用していました。
@Entity public class A { @Id private long id; private String name; @OneToMany private Set<B> b; }
@Entity public class B { @Id private long id; private String name; }
このとき、通常であればAに紐づくBのデータが無い場合、AのrepositoryからEntityを取得するとbはsizeが0の結果が取得できるはずです。(私はそう思っています) しかし、今回のパターンのように1つのトランザクション内で登録して取得しようとする際には注意が必要なようです。
私が失敗してしまった点
まず事前に必要なデータを入れるために以下のようなシンプル方法でデータを入れ、取り出しました。
A a = new A(); a.setId(1L); a.setName("test"); ARepository.save(a); A result = ARepository.findById(1L); result.getB() ← null
解決策
EntityManagerというものを使えばよいのです。
@PersistenceContext EntityManager entityManager;
さっきのに一行追加
A a = new A(); a.setId(1L); a.setName("test"); ARepository.save(a); entityManager.refresh(a); ← これを追加 A result = ARepository.findById(1L); result.getB() ← size0でちゃんと取得できる!
なぜこれで解決できたかというとEntityのライフサイクルが関係しているみたいなのですが、 大体は理解しているつもりなのですが、完全には理解しきってないので もし気になる方が複数人いらっしゃったら改めて深く勉強して今度まとめるかもしれないです。