読者です 読者をやめる 読者になる 読者になる

Play FrameworkのUnitTestで複数のテストでエラーとなる

Java Playframework

Play FrameworkのUnitTestですが、単独のテストは正常に実行できるけれども複数のテストを同時に実行すると必ず失敗するという不思議な状況に陥ってしまいました。

テストの内容はとても単純で、区分値に対応するモデルクラスについてyamlファイルからデータがロードできるかを確認するものです。

テストプログラム

[sourcecode language="java"] @Test public void TaxDivのデータをロードできる() {

Fixtures.loadModels("data/tax_div.yml");

int id = 1;
TaxDiv item = TaxDiv.findById(id);
assertThat(item, not(nullValue()));

assertThat(item.Name, is("内税"));
assertThat(item.Memo, is("メモ1"));
assertThat(item.DelFlg, is(false));

id = 2;
item = TaxDiv.findById(id);
assertThat(item, not(nullValue()));

id = 3;
item = TaxDiv.findById(id);
assertThat(item, not(nullValue()));

} [/sourcecode]

この結果でitemを取得しても必ずNullとなってしまい、テストが通らないという現象が発生しました。

いろいろと調べるもわからず、1時間ちょっといろいろ試してみました。当初は複数のテストが同時に走ることの副作用が発生しているのか?とか考えながらIntelliJ IDEAのJUnitの設定がどんなものかとか、データの消去方法をいろいろ変更してみたりしていたのですが、いっこうに解決の兆しは見られませんでした。

仕方がないのでDebug実行しながらPostgresでデータが生成される内容などを確認するのですが、JUnitでアサーションがfalseになるとトランザクションがロールバックされるようで、取得したいモデルについてはデータが常に空の状態になってしまっていました。

この辺がまた、なぜデータができないという方向へミスリードすることになりさらに混乱していました。

結局のところ、問題はModelを継承した場合に生成されるid列は hibernate_sequence というシーケンスから取得した値が設定されるためそれぞれの列でid=1のデータを取得するというようにするとうまくいかなくなるわけでした。

個人的にはserial値でいいのでテーブル毎にidを設定したと思うので、ここは Model ではなく GenericModel を継承したモデルを作成し、idを自分で作成するようにします。

idを自分で作成するように修正

[sourcecode language="java"] @Entity @Table(name = "tax_div") public class TaxDiv extends GenericModel {

@javax.persistence.Id
@Column(name="id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int Id;

@Column(name = "memo")
public String Memo;

@Column(name = "data_name")
public String Name;

@Column(name = "del_flg")
public boolean DelFlg;

} [/sourcecode]

これで、テーブルのidにはSerial型のデータが設定されるので問題は解決です。