2017-07-07 17 views
0

誰かが次のことを説明することはできますか?ハイバネーションテストの修正方法

@Entity 
public class Model { 

    @Id 
    @GeneratedValue(strategy = AUTO) 
    @Column 
    private long id; 

    @Column(length = 200, nullable = false) 
    private String field0; 

    @Column(length = 200, nullable = false) 
    private String field1; 

    @Column(length = 200, nullable = false) 
    private String field2; 

    @Column(length = 200, nullable = false) 
    private String field3; 

    @Column(length = 200, nullable = false) 
    private String field4; 

    @Column(length = 200, nullable = false) 
    private String field5; 

    @Column(length = 200, nullable = false) 
    private String field6; 

    @Column(length = 200, nullable = false) 
    private String field7; 

    @Column(length = 200, nullable = false) 
    private String field8; 

    @Column(length = 200, nullable = false) 
    private String field9; 

    public long getId() { 
     return id; 
    } 

    public void setId(long id) { 
     this.id = id; 
    } 

    public String getField0() { 
     return field0; 
    } 

    public void setField0(String field0) { 
     this.field0 = field0; 
    } 

    public String getField1() { 
     return field1; 
    } 

    public void setField1(String field1) { 
     this.field1 = field1; 
    } 

    public String getField2() { 
     return field2; 
    } 

    public void setField2(String field2) { 
     this.field2 = field2; 
    } 

    public String getField3() { 
     return field3; 
    } 

    public void setField3(String field3) { 
     this.field3 = field3; 
    } 

    public String getField4() { 
     return field4; 
    } 

    public void setField4(String field4) { 
     this.field4 = field4; 
    } 

    public String getField5() { 
     return field5; 
    } 

    public void setField5(String field5) { 
     this.field5 = field5; 
    } 

    public String getField6() { 
     return field6; 
    } 

    public void setField6(String field6) { 
     this.field6 = field6; 
    } 

    public String getField7() { 
     return field7; 
    } 

    public void setField7(String field7) { 
     this.field7 = field7; 
    } 

    public String getField8() { 
     return field8; 
    } 

    public void setField8(String field8) { 
     this.field8 = field8; 
    } 

    public String getField9() { 
     return field9; 
    } 

    public void setField9(String field9) { 
     this.field9 = field9; 
    } 

    @Override 
    public String toString() { 
     return "Model{" + "id=" + id + ", field0='" + field0 + '\'' 
       + ", field1='" + field1 + '\'' + ", field2='" + field2 + '\'' 
       + ", field3='" + field3 + '\'' + ", field4='" + field4 + '\'' 
       + ", field5='" + field5 + '\'' + ", field6='" + field6 + '\'' 
       + ", field7='" + field7 + '\'' + ", field8='" + field8 + '\'' 
       + ", field9='" + field9 + '\'' + '}'; 
    } 
} 


@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("/testContext.xml") 
public class MainTest { 

    @Autowired 
    private SessionFactory sessionFactory; 
    private Session session; 
    private Transaction tx; 

    @Before 
    public void before() { 
     session = sessionFactory.openSession(); 
     tx = session.beginTransaction(); 
     session.setFlushMode(FlushMode.COMMIT); 
    } 

    @After 
    public void after() { 
     tx.commit(); 
     session.close(); 
    } 

    @Test 
    public void shouldFindModelByField() { 
     Model model = createRandomModel(); 
     session.save(model); 

     model.setField0("TEST1"); 
     session.save(model); 

     assertTrue(null != session.createSQLQuery(
       "select id from model where field0 = '" + model.getField0() 
         + "'").uniqueResult()); 
    } 

    private Model createRandomModel() { 
     Model ret = new Model(); 
     ret.setField0(RandomStringUtils.randomAlphanumeric(10)); 
     ret.setField1(RandomStringUtils.randomAlphanumeric(10)); 
     ret.setField2(RandomStringUtils.randomAlphanumeric(10)); 
     ret.setField3(RandomStringUtils.randomAlphanumeric(10)); 
     ret.setField4(RandomStringUtils.randomAlphanumeric(10)); 
     ret.setField5(RandomStringUtils.randomAlphanumeric(10)); 
     ret.setField6(RandomStringUtils.randomAlphanumeric(10)); 
     ret.setField7(RandomStringUtils.randomAlphanumeric(10)); 
     ret.setField8(RandomStringUtils.randomAlphanumeric(10)); 
     ret.setField9(RandomStringUtils.randomAlphanumeric(10)); 
     return ret; 
    } 
} 

であるように私は、テストを実行する場合、テストが失敗したと私はエラーにjava.lang.AssertionErrorを取得する:私は、コードを持っています。

1)

@Test 
public void shouldFindModelByField() { 
    Model model = createRandomModel(); 
    session.save(model); 

    session.evict(model); 

    model.setField0("TEST1"); 
    session.save(model); 

    assertTrue(null != session.createSQLQuery(
      "select id from model where field0 = '" + model.getField0() 
        + "'").uniqueResult()); 
} 

2)

@Test 
public void shouldFindModelByField() { 
    Model model = createRandomModel(); 
    session.save(model); 

    model.setField0("TEST1"); 
    session.save(model); 

    tx.commit(); 
    tx = session.beginTransaction(); 

    assertTrue(null != session.createSQLQuery(
      "select id from model where field0 = '" + model.getField0() 
        + "'").uniqueResult()); 
} 

3)

@Test 
public void shouldFindModelByField() { 
    Model model = createRandomModel(); 
    session.save(model); 

    model.setField0("TEST1"); 
    session.save(model); 

    session.flush(); 

    assertTrue(null != session.createSQLQuery(
      "select id from model where field0 = '" + model.getField0() 
        + "'").uniqueResult()); 
} 

は私が成功したテストを実行する方法を@Test変更するために、3つのvarintsを持っています質問: 1)そのまま実行するとテストが失敗するのはなぜですか? 2)どのような変種が正しいですか? 3)それらのどれもない場合、コードを修正する方法は?

+0

Fix#1以外はすべて説明できます。あなたは 'evict()'と 'save()'を追加しただけですか?ダブルチェックしていただけますか?また、あなたのDBは何ですか? –

+0

最初に「保存」した後にevictを追加しました。私のdbはH2です。 XMLファイルhttp://prntscr.com/fswg10のスクリーンショットをご覧ください。上記の質問にお答えいただければ幸いです。 – ru51an

答えて

1

HibernateはHibernateは、実際のSQL文を生成するときにSQL

  • FlushModeが指示を実行。デフォルト(自動)はかなり賢明で、できるだけステートメントを遅らせようとします。しかし、それは各SELECTステートメントの前にフラッシュされます(そうしないと、永続化したレコードが見つかりません)。
  • HibernateはエンティティのIDを生成する必要があります(save()の結果はIDを持たなければならないPERSISTEDエンティティです)。したがって、どのFlushModeをORMとして選択しても、IDが生成されるために必要な場合は、INSERT文が発行されます。シーケンスジェネレータを使用する場合 - INSERTは延期することができますが、IDを使用します - このIDはINSERTの間にDBによって生成されるため、延期することはできません。

元のコードが

動作しないのはなぜあなたはFlushModeは、Hibernateはトランザクションのコミット直前にSQLを実行意味COMMITに設定します。したがって、エンティティを更新すると、UPDATE文は呼び出されません。トランザクションをコミットするときにのみ呼び出されます(これは決して行いません)。

なぜ#1を修正し、新たなエンティティの

あなたのオリジナルのINSERT文はまだCOMMITでもFlushModeで実行し、「作品」 - IDは右、生成する必要がありますか?

evict()エンティティHibernateはそれについてもう知らない。 save()の場合、Hibernateはこれが新しいオブジェクトだと思うので、新しいIDを生成する必要があるため、再度挿入します。

元のエンティティを更新する代わりに、実際に新しい行が挿入され、DB内に2つのオブジェクトが追加されます。 2番目のフィールドが選択されているため(フィールドがすでに正しい値に設定されているため)、テストに合格します。

はなぜHibernateはUPDATEステートメントを含むすべてのSQLをフラッシュするように、あなたが実際にトランザクションをコミット、まあ#2作品

を修正します。 FlushMode = COMMITは正常に動作します。

は、なぜこのような場合、あなた手動flush()変更で#3作品

を修正 - それは、SQL文あなたが選択したフラッシュモードに関係なく実行されます。テスト

を休止すべてSpringJUnit4ClassRunnerの初の書き方を

はテストで@Transactional注釈をサポートしています。したがって、手動でトランザクションを処理する代わりに@Before & @Afterを使用することができます。

第2に、テストが実際に機能することを確認するには、第1レベルのキャッシュを手動でフラッシュしてクリアする必要があります。そうしないと、実際のDBの代わりにキャッシュされたエンティティで作業する危険性があります。だからあなたのテストは次のようになります。

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("/testContext.xml") 
@Transactional 
public class MainTest { 
    ... 
    @Test public void canUpdateAllTheFields() { 
     Model original = createRandomModel(); 
     session.save(original); 
     session.flush(); 
     session.clear(); 

     Model updates = createRandomModel(); 
     model.setId(original.getId()); 
     session.update(updates); 
     session.flush(); 
     session.clear(); 

     assertReflectionEquals(updates, session.get(Model.class, original.getId())); 
    } 
} 

ノート:

  • あなたはフラッシュ()を組み合わせることができ、別の方法で()明確なその多くのスペースを取りませんように。
  • assertReflectionEquals()はUnitils libに由来します。

このようなテストの例は、here(TestNG)とhere(Spock)です。

+0

このような詳細なお返事ありがとうございます。 Before and After注釈の代わりにTransactional注釈を使用する方法を説明してください。 – ru51an

+0

答えを更新しました –

関連する問題