2011-12-21 14 views
6

Mam problem z wypychaniem zmian wprowadzonych w ramach transakcji hibernacji do bazy danych, aby program DbUnit działał poprawnie w moim przypadku testowym. Wygląda na to, że DbUnit nie widzi zmian wprowadzonych przez Hibernate, ponieważ nie są one jeszcze zatwierdzone na końcu transakcji ... i nie jestem pewien, jak zrestrukturyzować mój test, aby to zadziałało.Uzyskiwanie funkcji DbUnit do pracy z transakcją hibernacji

Oto moja nadmiernie uproszczony przypadek testowy do wykazania mój problem: -

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { 
     "classpath:applicationContext-test.xml" 
}) 
@TransactionConfiguration(transactionManager = "transactionManager") 
@Transactional 
public class SomeTest { 
    @Autowired 
    protected DataSource dataSource; 

    @Autowired 
    private SessionFactory sessionFactory; 

    @Test 
    public void testThis() throws Exception { 
     Session session = sessionFactory.getCurrentSession(); 

     assertEquals("initial overlayType count", 4, session.createQuery("from OverlayType").list().size()); 

     //----------- 
     // Imagine this block is an API call, ex: someService.save("AAA"); 
     // But for the sake of simplicity, I do it this way 
     OverlayType overlayType = new OverlayType(); 
     overlayType.setName("AAA"); 
     session.save(overlayType); 
     //----------- 

     // flush has no effect here 
     session.flush(); 

     assertEquals("new overlayType count", 5, session.createQuery("from OverlayType").list().size()); 

     // pull the data from database using dbunit 
     IDatabaseConnection connection = new DatabaseConnection(dataSource.getConnection()); 
     connection.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new MySqlDataTypeFactory()); 
     QueryDataSet partialDataSet = new QueryDataSet(connection); 
     partialDataSet.addTable("resultSet", "select * from overlayType"); 
     ITable actualTable = partialDataSet.getTable("resultSet"); 

     // FAIL: Actual row count is 4 instead of 5 
     assertEquals("dbunit's overlayType count", 5, actualTable.getRowCount()); 

     DataSourceUtils.releaseConnection(connection.getConnection(), dataSource); 
    } 
} 

Moja cała idea w użyciu DBUnit jest: -

  • połączeń someService.save(...) który zapisuje dane w kilku tabelach.
  • Użyj DbUnit, aby uzyskać oczekiwany zbiór z pliku XML.
  • Użyj DbUnit, aby pobrać aktualną tabelę z bazy danych.
  • Do Assertion.assertEquals(expectedTable, actualTable);.

Ale w tym momencie nie jestem w stanie uzyskać DbUnit, aby zobaczyć zmiany dokonane przez Hibernate w ramach transakcji.

Jak powinienem się zmienić, aby DbUnit działał dobrze z transakcją hibernacji?

Dzięki.

Odpowiedz

9

Nigdy nie pracowałem z DBUnit, ale wydaje się, że TransactionAwareDataSourceProxy rade. Zasadniczo trzeba zawinąć oryginalnego źródła danych z tego serwera proxy i używać go zamiast, tak, że ten kod:

new DatabaseConnection(dataSource.getConnection()) 

faktycznie przechodzi przez proxy i wykorzystuje tę samą transakcję i połączenie jak Hibernate.

Znalazłem Transaction aware datasource (use dbunit & hibernate in spring) wpis na blogu wyjaśniający to.

Innym podejściem byłoby całkowite pominięcie testów transakcyjnych i ręczne wyczyszczenie bazy danych. Sprawdź mój artcle transactional tests considered harmful.

+0

+1 Dobra odpowiedź Tomasz! – Nilesh

0

Wygląda na to, że ten przypadek testowy wymaga dwóch transakcji: jednej do umieszczenia danych w bazie danych, a drugiej do jej pobrania.

Co chciałbym zrobić, to:

  • używać bazy danych pamięci więc dane są czyszczone po zakończeniu testów jednostkowych.
  • Usuń adnotacje transakcyjne i użyj metod beginTransaction i zatwierdzeń sesji bezpośrednio.

Początkowa liczba overlaytype będzie 0, a po sesji jest zapisane, powinno być 1.

Powiązane problemy