2014-10-07 5 views
5

Wenn ich dbunit mit dem folgenden Setup ausführen und Daten über HTTP in einem Integrationstest anfordern, habe ich keine Daten erhalten, weil die Datenbank ist leer. DBUnit schreibt Daten in die Datenbank, aber es ist leer, wenn ich die Daten über HTTP anfordere.DBUnit und Spring Boot - Daten können nicht importiert werden oder existieren bei Anforderung in einem Integrationstest

Das ist mein Setup: Spring Boot 1.1.7 mit Spring-Boot-Starter-Web (ausgenommen Tomcat), Spring-Boot-Starter-Steg, Spring-Boot-Starter-Daten-Jpa, Spring-Boot- Starter-Test, Liquibase-Kern, DBUnit 2.5.0, feder Test-DBUnit 1.1.0

Hauptanwendungsklasse:

@Configuration 
@ComponentScan 
@EnableAutoConfiguration 
@RestController 
@EnableTransactionManagement 
@EnableJpaRepositories 

Test-Konfiguration (anwendungs ​​test.yaml):

logging.level.org.springframework: DEBUG 
logging.level.org.dbunit: DEBUG 

spring.jpa.properties.hibernate.hbm2ddl.auto: update 
spring.jpa.database: h2 
spring.jpa.show-sql: true 

// setting these properties to access the database via h2 console 
spring.datasource.url: jdbc:h2:tcp://localhost/mem:my_db;DB_CLOSE_DELAY=-1;MVCC=true;DB_CLOSE_ON_EXIT=FALSE 
spring.datasource.username: sa 
spring.datasource.password: sa 
spring.datasource.driverClassName: org.h2.Driver 
spring.jpa.database-platform: org.hibernate.dialect.H2Dialect 

liquibase.change-log: classpath:/db/changelog/db-master.xml 

Integ Ration Test:

@ActiveProfiles("test") 
@RunWith(SpringJUnit4ClassRunner.class) 
@SpringApplicationConfiguration(classes = HDImageService.class) 
@TestExecutionListeners({ 
    DependencyInjectionTestExecutionListener.class, 
    DbUnitTestExecutionListener.class }) 
@WebAppConfiguration 
@IntegrationTest("server.port:0") 
@DatabaseSetup("/database_seed.xml") 
@DatabaseTearDown(value = "/database_tear_down.xml", type = DatabaseOperation.DELETE_ALL) 

// test 
@Test 
public void get_works() throws Exception { 
    // given 
    String url = host + port + "/my-resource/1"; 

    // when 
    ResponseEntity<String> response = template.getForEntity(url, String.class); 

    // then 
    assertThat(response.getStatusCode(), is(HttpStatus.OK)); 
} 

Ich konnte alles Anderem hier, wie die Einheiten, Repository, Controller, ... aber diese Komponenten arbeiten, weil ich bereits im Test über das injizierte Repository in die Datenbank schreiben und erhalten es über HTTP. Also das Problem ist der Import über dbunit, der nicht funktioniert ... Ich habe dbunit bereits erfolgreich in einem älteren projected verwendet, aber nicht zusammen mit Spring Boot. Vielleicht arbeiten die Ausführung Listener nicht ähnlich mit Spring Boot?

Ich Debugging warf die Klassen von dbunit und lesen Sie alle Debug-Log-Ausgabe, aber ich verstehe es nicht. DBUnit verwendet die Spring-Boot-DataSource (die oben konfigurierte), so dass es die gleiche Datenbank ist.

Wenn die Tests Integration beginnen, ist folgende Ereignisse eintreten:
- liquibase das Datenbankschema erstellt auf der Grundlage der liquibase Konfiguration
- DBUnit in die Datenbank einfügen (sagt das Protokoll (vielleicht JPA bereits vor das Schema geschoben?)

ich bin auf der Suche nach einem alt: - Ausgabe und Debugging)
Get 404 nicht (ich kehre in der Datenbank mit der angegebenen ID)

aktualisiert 404, wenn kein Eintrag gefunden wurde erative zu dbunit, kann aber keine gute Lösung finden. Wie bereiten Sie Ihre Datenbank auf Ihre Integrationstests vor? Eigentlich muss ich nur einzelne Daten vor jedem Test oder Test importieren, wenn die Daten wie erwartet erhalten bleiben.

aktualisieren:

ich die folgenden Optionen verwenden, um die h2-Datenbank zu verbinden.

DB_CLOSE_DELAY=-1;MVCC=true;DB_CLOSE_ON_EXIT=FALSE 

Wenn ich die kompletten spring.datasource entfernt * Konfiguration Feder ist die Datenquelle mit Standardwerten zu schaffen und starten Sie einen In-Memory-H2-Datenbankserver. Dies wird ohne die Optionen ausgeführt, die ich erwähnt habe, und ich bekomme eine org.hibernate.PessimisticLockException, weil dbunit immer noch die Datenbanktabelle sperrt und die HTTP-Anfrage, die innerhalb des Tests gesendet wurde, keinen Zugriff auf die Datenbanktabelle hat. Dies liegt an der Option MVCC=true;, die höhere Parallelität hinzugefügt hat, was im Grunde das Problem ist, warum keine Daten vorhanden sind: "Nur Verbindungen" sehen "festgeschriebene Daten und eigene Änderungen". Beim Zugriff auf die Datenbank über die HTTP-Anfrage sind die Daten von dbunit nicht vorhanden, da die Daten von dbunit nicht für die Federverbindung festgelegt sind ...

Also, weiß jemand, warum die h2 (und auch Derby) Datenbanktabelle (n) von dbunit gesperrt sind?

Antwort

5

Ich habe endlich eine Lösung für dieses Problem gefunden.

Es war die richtige Richtung mit der PessimisticLockException wo ich darauf hingewiesen habe. DBUnit hat die Datenbankverbindung nicht freigegeben, deshalb konnte die Verbindung von spring nicht auf die Datenbanktabelle (n) zugreifen, die gesperrt waren.

Ich habe meine eigene Datenbankoperation implementiert. Ich habe die Option customize DBUnit database options verwendet.

Zunächst einmal implementiert ich eine Klasse AutoCommitTransactionOperation auf der Grundlage der TransactionOperation von DBUnit genannt, mit dem Unterschied, dass ich den Scheck entfernt jdbcConnection.getAutoCommit() == false und rettete die Auto-Wert verpflichten, bevor die automatische Commit auf false setzen. Nach dem Festschreiben habe ich den Wert zurück, mit dem gespeicherten Wert wie den gleichen Zustand zu haben, bevor:

public class AutoCommitTransactionOperation extends DatabaseOperation { 

    private final DatabaseOperation _operation; 

    public AutoCommitTransactionOperation(DatabaseOperation operation) { 
     _operation = operation; 
    } 

    public static final DatabaseOperation AUTO_COMMIT_TRANSACTION(DatabaseOperation operation) { 
     return new AutoCommitTransactionOperation(operation); 
    } 

    public void execute(IDatabaseConnection connection, IDataSet dataSet) throws DatabaseUnitException, SQLException { 
     logger.debug("execute(connection={}, dataSet={}) - start", connection, dataSet); 

     IDatabaseConnection databaseConnection = connection; 
     Connection jdbcConnection = databaseConnection.getConnection(); 

     boolean autoCommit = jdbcConnection.getAutoCommit(); 
     jdbcConnection.setAutoCommit(false); 
     try { 
      _operation.execute(databaseConnection, dataSet); 
      jdbcConnection.commit(); 
     } catch (DatabaseUnitException e) { 
      jdbcConnection.rollback(); 
      throw e; 
     } catch (SQLException e) { 
      jdbcConnection.rollback(); 
      throw e; 
     } catch (RuntimeException e) { 
      jdbcConnection.rollback(); 
      throw e; 
     } finally { 
      jdbcConnection.setAutoCommit(autoCommit); 
     } 
    } 
} 

Dann habe ich die DatabaseLookup.

public class AutoCommitTransactionDatabaseLookup extends DefaultDatabaseOperationLookup { 

    @Override 
    public org.dbunit.operation.DatabaseOperation get(DatabaseOperation operation) { 
     if (operation == operation.CLEAN_INSERT) { 
      return AutoCommitTransactionOperation.AUTO_COMMIT_TRANSACTION(org.dbunit.operation.DatabaseOperation.CLEAN_INSERT); 
     } 
     return super.get(operation); 
    } 
} 

und es zu meiner Testklasse:

@DbUnitConfiguration(databaseOperationLookup = AutoCommitTransactionDatabaseLookup.class) 

Ich bin nicht sicher, ob dies mehr hacken ... irgendwelche Hinweise auf meine Hack?

+0

Ich finde es absolut genial, dass Sie Ihre Lösung in solch einer Menge an Details geteilt haben. Ich glaube, ich habe das gleiche Problem bei der Arbeit, obwohl in meinem eigenen Dummy-Projekt zu Hause funktioniert es sowohl mit als auch ohne Ihre Lösung. Ich werde es am Montag bei der Arbeit versuchen, das ist sicher. –

+0

Danke! Hast du das gleiche Problem? – David

Verwandte Themen