2013-08-22 3 views
0

J'essaie de créer des cas de test pour @Transactional.Échec du test transactionnel

@ContextConfiguration(locations = {"classpath:/META-INF/spring/app-context.xml" }) 
@RunWith(SpringJUnit4ClassRunner.class) 
public class TransactionalAnnotationTest { 
    public static final BigDecimal PROD_ID = new BigDecimal(1234); 

    @PersistenceContext 
    HibernateEntityManager em; 


    @Test 
    public final void testTransactionIsolation() { 
     String original = em.find(ProductImpl.class, PROD_ID).getDescription(); 
     // original = "Foo" 
     updateTx(original); 
    } 

    @Transactional 
    public final void updateTx(String original) { 
     ProductImpl product = em.find(ProductImpl.class, PROD_ID); 
     product.setDescription("Bar"); 
     whatIsInDB(original); 
    } 

    private void whatIsInDB(String original) { 
     String sameTxDescription = em.find(ProductImpl.class, PROD_ID).getDescription(); 
     assert !sameTxDescription.equals(original); 
    } 
} 

Il échoue! Le second em.find ne doit-il pas renvoyer un produit avec "Bar"?

+0

Je pense que vous vouliez dire 'un produit avec "Bar"' –

+0

Merci u'r droite. –

+0

Ai-je raison que '@ Transactional' est pour les beans gérés par Spring qui sont auto-gérés seulement ??? –

Répondre

-1

Hm, je l'ai eu à travailler.

  1. Pour tester Transactions: un simple em.flush() est tout ce dont j'ai besoin (merci à @TaoufikMohdit pour l'idée). S'il n'y a pas de transaction, flush() lance un TransactionRequiredException!
  2. @Transactional est uniquement pour les haricots à gestion Spring. Donc, je crée un service:

    @Service 
    public class BasicTransactionalService { 
        @PersistenceContext 
        HibernateEntityManager em; 
    
        @Transactional 
        public void testFlushInTransactional() { 
        em.flush(); 
        } 
    
        @Deprecated 
        public void testFlushOutsideTransactional() { 
        em.flush(); 
        } 
    
        @Transactional 
        public void testFlushSubroutineTransactional() { 
        testFlushOutsideTransactional(); 
        } 
    } 
    
  3. J'ai changé les tests à:

    @Autowired 
    BasicTransactionalService bean; 
    
    @Test 
    public void testTransactionIsolation() { 
        bean.testFlushInTransactional(); 
    } 
    
    @Test(expected = TransactionRequiredException.class) 
    @SuppressWarnings("deprecation") 
    public void testThrowsTransactionRequiredException() { 
        bean.testFlushOutsideTransactional(); 
    } 
    
    @Test 
    public void testTransactionalSubroutine(){ 
        bean.testFlushSubroutineTransactional(); 
    } 
    

Maintenant, il fonctionne très bien.

BTW Ceci est mon app-config.xml

<beans> 
    <bean class="BasicTransactionalService" /> 
    <bean class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean" /> 
    <bean class="org.springframework.orm.jpa.JpaTransactionManager" /> 
    <tx:annotation-driven /> 
<beans> 
0

essayez de vider explicitement le contexte après avoir défini la "description" champ

product.setDescription("Bar"); 
em.flush(); 
whatIsInDB(original); 

+0

Non, 'flush()' écrit sur db. 'whatIsInDB' n'aurait aucun sens après' flush'. –

+0

Désolé, je viens d'avoir votre sens de test maintenant. Je serais curieux de savoir quel est le mode flush (em.getFlushMode()), si ce n'est pas AUTO ou ALWAYS, cela pourrait expliquer l'échec du test. –

+0

'em.getFlushMode()' retourne 'AUTO' dans' testTransactionIsolation', 'AUTO' dans' updateTx' et 'AUTO' dans' whatIsInDB'. –