2016-09-29 2 views
0

のために動作しません。私は、次のtecnologiesを使用します。はsessionFactory.getCurrentSessionを休止状態()フラッシュ()テスト

  • TestNGの(6.9.10)
  • 春(4.3.2.RELEASE)

にJavaの8

  • (5.1.0.Final)を休止私は統合テストによって機能をいくつかのコードをテストし、私は更新/削除/保存正しいまたはその他の変更のためのエンティティをチェックする必要があります。

    <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean" 
         p:dataSource-ref="dataSource" p:hibernateProperties="jdbcProperties"> 
        <property name="packagesToScan" value="my.package"/> 
    </bean> 
    

    とテストクラス例:

    @ContextConfiguration(locations = {"classpath:/applicationContext-test.xml", 
        "classpath:/applicationContext-dao.xml", 
        "classpath:/applicationContext-orm.xml"}) 
    public class AccountServiceTest extends AbstractTransactionalTestNGSpringContextTests { 
    
    @Autowired 
    private SomeService someService; 
    @Autowired 
    private SessionFactory sessionFactory; 
    
    @Test 
    public void updateEntity() { 
        //given 
        Long entityId = 1L; 
        SomeClass expected = someService.get(entityId); 
        String newPropertyValue = "new value"; 
        //when 
        someService.changeEntity(entity, newPropertyValue); 
        // Manual flush is required to avoid false positive in test 
        sessionFactory.getCurrentSession().flush(); 
        //then 
        expected = someService.get(entityId); 
        Assert.assertEquals(expected.getChangedProperty() , newPropertyValue); 
    } 
    

    サービス方法:

    @Transactional 
    @Override 
    public int changeEntity(entity, newPropertyValue) { 
        return dao().executeNamedQuery(REFRESH_ACCESS_TIME_QUERY, 
          CollectionUtils.arrayToMap("id", entity.getId(), "myColumn", newPropertyValue)); 
    } 
    

    DAO:

    @Override 
    public int executeNamedQuery(final String query, final Map<String, Object> parameters) { 
        Query queryObject = sessionFactory.getCurrentSession().getNamedQuery(query); 
        if (parameters != null) { 
         for (Map.Entry<String, Object> entry : parameters.entrySet()) { 
          NamedQueryUtils.applyNamedParameterToQuery(queryObject, entry.getKey(), entry.getValue()); 
         } 
        } 
        return queryObject.executeUpdate(); 
    } 
    
    の.xmlSessionFactoryの設定があります。

    しかし、ここで説明したように私のエンティティプロパティは、)(フラッシュ後change @Autowire SessionFactory with @PersistenceContext EntityManager

    を変更していない、私はflush()EntityManagerを使用する必要があります - しかし、私はこれを行うことはできません - 私はEntityManagersessionFactoryを変換することができず、私は自分のアプリケーションにEntityManagerを作成する必要はありません。.xml設定ファイルなどを変更する必要があるためです。

    この問題の別の解決方法はありますか?

  • +0

    何が問題なのですか? 'EntityManager'や' SessionFactory'を使用しても違いはありません。あなたのポストにあなたのサービスとDAOを追加してください。 –

    +0

    私にとって、 'EntityManager'は' Session'と共通していて、 'SessionFactory'とはもっと共通しています。 – Antoniossss

    +0

    正しい。しかし、単純な休止状態またはJPA抽象化とそれらの1つをフラッシュすることを使用することは重要ではありません。したがって、何が動作していないか、より多くのコードについての追加情報の要求。 –

    答えて

    0

    コードは実際には期待どおりに動作しています。

    あなたのテスト方法はトランザクションであり、したがって、あなたのSessionはテストメソッドの実行中に生きています。 Sessionは、休止状態用の第1レベルのキャッシュでもあり、データベースからエンティティをロードするときにセッションに入れられます。

    したがって、SomeClass expected = someService.get(entityId);行はデータベースからエンティティを読み込み、Sessionにも入ります。

    この行expected = someService.get(entityId);最初のチェック(実際には下のdaoメソッド)は、idを持つ要求された型のエンティティが既に存在する場合は、Sessionに存在するかどうかを確認します。それはではなく、データベースをクエリ!

    主な問題は、間違った方法で休止状態を使用していることです。基本的には、データベースを更新する方法で休止状態を回避しています。エンティティを更新して保持する必要があります。データベースを更新するためのクエリを書くべきではありません!

    テストメソッドのみテストがflush()clear()への呼び出しを追加する修正するには

    @Test 
    public void updateEntity() { 
        //given 
        Long entityId = 1L; 
        SomeClass expected = someService.get(entityId); // load from db and put in Sesion 
        String newPropertyValue = "new value"; 
        //when 
        someService.changeEntity(entity, newPropertyValue); // update directly in database bypass Session and entity 
        // Manual flush is required to avoid false positive in test 
        sessionFactory.getCurrentSession().flush(); 
        //then 
        expected = someService.get(entityId); // return entity from Session 
        Assert.assertEquals(expected.getChangedProperty() , newPropertyValue); 
    } 
    

    sessionFactory.getCurrentSession().clear(); 
    

    は、しかし、あなたが実際に何をすべきか、そのようなコードを書いて停止し、正しい方法でHibernateと永続エンティティを使用しています。

    @Test 
    public void updateEntity() { 
        //given 
        Long entityId = 1L; 
        String newPropertyValue = "new value"; 
    
        SomeClass expected = someService.get(entityId); 
        expected.setMyColumn(newPropertyValue); 
    
        //when 
        someService.changeEntity(entity); 
    
        sessionFactory.getCurrentSession().flush(); 
    
        // now you should use a SQL query to verify the state in the DB. 
        Map<String, Object> dbValues = getJdbcTemplate().queryForMap("select * from someClass where id=?", entityId); 
        //then 
        Assert.assertEquals(dbValues.get("myColumn"), newPropertyValue); 
    } 
    

    あなたのDAOメソッドは、次のようになります。

    public void changeEntity(SomeClass entity) { 
        sessionFactory.getCurrentSession().saveOrUpdate(entity); 
    } 
    
    +0

    私が見つけたように - 私はサービスメソッドを呼び出すとsetterを介して直接値を変更しない - 私はちょうどupdate()を使用して、すべてがうまくいます - 私はエンティティを再び取得することができます(キャッシュから - トランザクションがコミットされないため)変更されたプロパティが表示されます。このためにflush()を使用すべきではありません。しかし、問題は私のサービスメソッド内に名前付きのクエリがあり、クエリqueryObjectのexecuteUpdate()を呼び出すことです –

    +0

    あなたは実際に私のコメントと答えを読んだことがありますか?私は両方のオプションの答えを与えた。それにもかかわらず、クエリで物事を更新することは、休止状態の環境では間違っているだけです。しかし、最後の部分だけではなく、私の答えをもう一度読んでください。 –