2015-02-23 9 views
7

Wszystkie metody MyService są transakcyjne. Test JUnit poniżej, dostaje liczbę przedmiotów, zapisuje nowy element, a następnie pobiera liczbę elementów, aby upewnić się, że liczy został zwiększony o 1.Spring @transaction nie działa zgodnie z oczekiwaniami w junit w trybie bez debugowania

public class MyTest extends ServiceTest{ 

    1. int countBefore = myService.getCount(); //return n 
    2. myService.add(item);      //item is really added to DB 
    3. int countAfter = myService.getCount(); //return n (sometimes n+1) 
} 

@Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.READ_COMMITTED) 
getCount(){…} 

@Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.SERIALIZABLE) 
add(){…} 

@Ignore 
@ContextConfiguration(locations = { "file:src/main/resources/xxx-context.xml", 
            "file:src/main/resources/xxx-data.xml", 
            "file:src/main/resources/xxx-services.xml" }) 
@TransactionConfiguration(transactionManager = "txManager", defaultRollback = false) 
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, 
          DirtiesContextTestExecutionListener.class, 
          TransactionalTestExecutionListener.class, 
          TestListener.class}) 

public class ServiceTest extends AbstractUT{ 

@Ignore 
@RunWith(SpringJUnit4ClassRunner.class) 
@TestExecutionListeners({TestListener.class}) 
public class AbstractUT{ 

Gdy debugowanie (3.) zwraca n + 1, co jest tym czego chcę. Ale podczas uruchamiania testu bez debugowania otrzymuję n.

Nawet czasami, gdy wykonuję test, otrzymuję n + 1 i następnym razem otrzymam n, a przy porównaniu wyjścia standardowego między dwoma wykonaniami, wygląda dokładnie tak samo. Mam włączone log4j.logger.org.springframework.transaction = śladowych i widzę:

Initializing transaction synchronization 
Getting transaction for MyService.getCount 
... 
Completing transaction for MyService.getCount 
Clearing transaction synchronization 

... 

Initializing transaction synchronization 
Getting transaction for MyService.add 
... 
Completing transaction for MyService.add 
Clearing transaction synchronization 

... 

Initializing transaction synchronization 
Getting transaction for MyService.getCount 
... 
Completing transaction for MyService.getCount 
Clearing transaction synchronization 

więc transakcje są wykonywane jedna po drugiej, ale jak to możliwe, że (3) nie widać zapisany przedmiot?

managment transakcja jest w mojej klasie konfiguracji testowej według: https://stackoverflow.com/a/28657650/353985

Jak mogę znaleźć to, co jest nie tak? Dzięki!

+0

Czy używasz ''? tak czy inaczej zobacz moją odpowiedź na [ten link] (http://stackoverflow.com/a/25910635/3364187). – Xstian

+0

Absolutnie tak. – redochka

+0

Czy możesz dodać konfigurację i swój TestClass? – Xstian

Odpowiedz

3

Miałem podobny problem, ale w moim przypadku nie został on wycofany. Wygląda na to, że zapomniałeś dodać @Transactional. Z dokumentacją (link)

zarządzanie transakcjami

W ramach TestContext transakcje są zarządzane przez TransactionalTestExecutionListener który jest skonfigurowany domyślnie nawet jeśli nie jawnie zadeklarować @TestExecutionListeners na własną Klasa testowa. Aby włączyć obsługę transakcji, należy jednak skonfigurować komponent bean PlatformTransactionManager w ApplicationContext , który jest ładowany za pomocą semantyki @ContextConfiguration (dalsze szczegóły: podano poniżej). Ponadto należy zadeklarować wiosenną @ Adnotację transakcyjną na poziomie klasy lub metody dla testów .

Oto przykład formularza powyżej.

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration 
@TransactionConfiguration(transactionManager="txMgr", defaultRollback=false) 
@Transactional 
public class FictitiousTransactionalTest { 

@BeforeTransaction 
public void verifyInitialDatabaseState() { 
    // logic to verify the initial state before a transaction is started 
} 

@Before 
public void setUpTestDataWithinTransaction() { 
    // set up test data within the transaction 
} 

@Test 
// overrides the class-level defaultRollback setting 
@Rollback(true) 
public void modifyDatabaseWithinTransaction() { 
    // logic which uses the test data and modifies database state 
} 

@After 
public void tearDownWithinTransaction() { 
    // execute "tear down" logic within the transaction 
} 

@AfterTransaction 
public void verifyFinalDatabaseState() { 
    // logic to verify the final state after transaction has rolled back 
} 

}

+0

Zauważyłem, że powiedziałeś, że twoje metody mają @Transactional, ale wciąż musiałem dodać je na moich poziomach metod dla moich testów. – kyla

+0

Nawet dodając @Transactional do metody testowej, otrzymuję to samo zachowanie. – redochka

+0

jaka jest Twoja rozmowa na temat twoich transakcji? – kyla

0

Roztwór I znaleziono dotychczas przejść test jest umieścić dochodzić w metodzie afterTransaction

klasy publicznej MyTest rozciąga ServiceTest {

@Test 
public void test(){ 
    1. int countBefore = myService.getCount(); //return n 
    2. myService.add(item);      //item is really added to DB 
} 
 
@AfterTransaction 
public void verifyFinalDatabaseState() { 
    3. int countAfter = myService.getCount(); //
            
 
  
             return n (sometimes n+1)
            
  
                //Now always return n+1 
} 
0

Ponieważ bieżąca transakcja jest ustawiona na test method level, masz dwie opcje:

  1. Albo usunąć @Transactional od metody badania i opierają się na metodzie usług @Transactional granic. W ten sposób podczas rozmowy:

    int countBefore = myService.getCount(); 
    myService.add(item); 
    int countAfter = myService.getCount(); 
    

Każde wywołanie usługa będzie działać w izolowanym transakcji, podobnie jak to się dzieje w zaproszeniu produkcji run-time.

  1. można opróżnić sesji hibernacji, tuż po dodaniu urządzenia:

    int countBefore = myService.getCount(); 
    myService.add(item); 
    transactionTemplate.execute(new TransactionCallback<Void>() { 
        @Override 
        public Company doInTransaction(TransactionStatus transactionStatus) { 
         entityManager.flush(); 
         return null; 
        } 
    }); 
    int countAfter = myService.getCount(); 
    

HQL Query/Ilość JPQL powinno uruchamiać kolor w trybie automatycznego spłukiwania , ale an SQL native query doesn't flush the Session.

+0

Próbowałem już obie opcje odpowiedzi. 1- Mój test nie jest @ transakcyjny, 2- Nie mam entityManager, używam sessionFactory.getCurrentSession.flush() Nadal dostaję to samo dziwne zachowanie. Jedyną rzeczą, która działa do tej pory, jest assert w @ AfterTransaction. Zobacz moją odpowiedź. – redochka

+0

Można również użyć sesji Hibernacja. Spróbuj z 'transactionTemplate', tak jak sugerowałem. –

0

Chciałbym zapytać o to w komentarzu, ale ponieważ moja reputacja na to nie pozwala, chciałbym po prostu podać odpowiedź.

Możliwe, że używasz i ORM, która przechowuje wyniki kwerendy liczenia. W zależności od sposobu implementacji metod add/getCount oraz konfiguracji ORM i źródła danych podczas drugiej inwokacji getCount można uzyskać buforowaną wartość uzyskaną podczas pierwszego wywołania metody getCount.

Nie wyjaśnia to jednak, dlaczego w trybie debugowania zawsze uzyskuje się poprawny wynik.

+0

Używam hibernacji, a twój pomysł też do mnie przychodzi. Jak obejść pamięć podręczną trybu hibernacji? – redochka

+0

zajrzyj tutaj [Konfiguracja hibernacji] (https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/session-configuration.html) Tabela 3.5. Wierzę, że hibernate.cache.use_query_cache i hibernate.cache.use_second_level_cache byłyby dla Ciebie interesujące. Spróbuj ustawić zarówno false w konfiguracji hibernacji. –

Powiązane problemy