web-dev-qa-db-fra.com

L'isolement du test d'intégration échoue au démarrage de printemps 2.2.2.RELEASE (erreur lors de la suppression des tables après chaque SpringBootTest)

Notre application fonctionne dans la version 2.0.4. Après la mise à niveau vers 2.2.2.RELEASE, les tests d'intégration échouent. Je soupçonne qu'il y a une mauvaise configuration, et chaque test d'intégration ne nettoie tout simplement pas après lui-même ou il y a une initialisation supplémentaire qui n'était pas là avant. Je ne sais vraiment pas comment le réparer correctement.

Pour être précis. Chaque test fonctionne lorsqu'il est appelé séparément. Une fois exécutés, nous voyons des erreurs comme:

org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "drop table somewhere.sometable if exists" via JDBC Statement
...
caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Cannot drop "SOME_TABLE" because "FKKJEJC7GUX6OTX5NGANQCMN83R, FK7WLRCFA21PY7CI3R4OL1OWODT, FKQPMY4YOVD3D6HBNT0XX92149P, FK1TG6AMM2NSM6UJTO9EJHPJIXY, FKLPTBKDKFCHE72RJ5RRRIH4ORJ" depends on it; SQL statement:

et

2019-12-16 21:11:00.075 org.Apache.Tomcat.util.modeler.Registry  : The MBean registry cannot be disabled because it has already been initialised

ce qui me suggère que nous essayons de réinitialiser quelque chose déjà initialisé + il y a un mauvais ordre de gouttes dans l'initialisation hibernate. Mais je ne vois vraiment rien de mal de notre côté. Voyons quelques extraits:

annotations de test:

@RunWith(SpringRunner.class)
@ActiveProfiles(...)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SomeIT {

les tests sont exécutés via:

<plugin>
  <groupId>org.Apache.maven.plugins</groupId>
  <artifactId>maven-failsafe-plugin</artifactId>
  <version>2.22.2</version>
  <configuration>
    <useSystemClassLoader>false</useSystemClassLoader>
    <forkCount>0</forkCount>
    <reuseForks>false</reuseForks>
  </configuration>
  <executions>
    <execution>
      <id>integration-test</id>
      <goals>
        <goal>integration-test</goal>
      </goals>
    </execution>
    <execution>
      <id>verify</id>
      <goals>
        <goal>verify</goal>
      </goals>
    </execution>
  </executions>
</plugin>

et application.properties pour les tests:

spring.jpa.database=H2
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.jdbc.batch_size=5
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.jdbc.batch_versioned_data=true

#this disables option to have opened tx in view IIUC. We don't rely on that, so this just removes warning logging from console.
spring.jpa.open-in-view=false

#used to select db initialization scripts.
spring.datasource.platform=org.hibernate.dialect.H2Dialect

spring.datasource.url=jdbc:h2:mem:somewhere;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;INIT=create schema if not exists somewhere
spring.datasource.driver-class-name = org.h2.Driver

#this is probably needed for @DataJpaTest: I have no idea how to configure @DataJpaTest so that it can run with
#autoconfigured H2 db, probably it's caused by having schema defined in entities. Anyways @DataJpaTest fails to
#create schema. So alternative is to configure one DB for whole app here, and this option forces all @DataJpaTest not to
#replace this configuration with autoconfigured db.
spring.test.database.replace=none

Modifications testées:

  • J'ai changé create en create-drop si cela aide de quelque façon que ce soit et non, cela n'aide en aucune façon.
  • J'ai essayé de @DirtiesContext au niveau de la classe pour chaque test informatique, ce que j'attendais de toute façon, ce contexte est créé/tué avec chaque classe de test informatique, mais cela n'a pas aidé non plus.
  • J'ai essayé de supprimer replace=none, mais cela tue tous les tests unitaires (car le schéma n'est pas créé), et n'aide en rien les tests d'intégration.

Solution actuelle: eh bien tout ce que j'ai pu trouver n'est pas de réutiliser db. Qui avec replace=none n'est possible que via:

spring.datasource.url=jdbc:h2:mem:somewhere${random.uuid};DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;INIT=create schema if not exists somewhere

mais je déteste profondément cette "solution". Qu'est-ce qui peut provoquer une réinitialisation incorrecte de la base de données/des nettoyages manquants/ou quelle pourrait être la cause de tout cela?

(modifier: si vous connaissez mieux le titre de cette question, veuillez le suggérer. Merci).

6
Martin Mucha

J'ai eu le même problème et malheureusement réponse de Melkor n'a pas fonctionné pour nous car notre schéma était trop complexe pour écrire un script supprimant les tables dans un ordre correct.

H2 prend en charge suppression de tous les objets quelles que soient leurs dépendances, le script suivant peut donc réinitialiser l'ensemble de la base de données.

src/test/resources/drop-tables.sql

DROP ALL OBJECTS

Ensuite, spécifiez les propriétés de test pour utiliser le script pour supprimer des tables

src/test/resources/application.properties

spring.jpa.properties.javax.persistence.schema-generation.drop-source=script
spring.jpa.properties.javax.persistence.schema-generation.drop-script-source=drop-tables.sql
1
hota911

Je voulais vous faire savoir que j'ai trouvé une solution à ce problème. Avec javax.persistence propriétés, vous pouvez définir un script de dépôt qui sera exécuté avant la création automatique du schéma.

Cela vous permet de spécifier l'ordre dans lequel les tables doivent être supprimées (dépendez d'abord des tables). Peut-être que jouer avec ceux-ci pourrait vous aider. Notez qu'ils remplacent le spring.jpa.hibernate.ddl propriété.

spring.jpa.properties.javax.persistence.schema-generation.database.action=drop-and-create
spring.jpa.properties.javax.persistence.schema-generation.drop-source=script-then-metadata
spring.jpa.properties.javax.persistence.schema-generation.drop-script-source=drop-tables.sql
0
Melkor