h2database - jdbc maven
¿Iniciando un servidor de base de datos H2 de Maven? (9)
Acabo de comenzar el proyecto para el complemento H2 para maven @ bitbucket. Apreciaré cualquier ayuda con eso.
https://bitbucket.org/dohque/maven-h2-plugin
Espero que sea de ayuda.
Supongamos que quiero crear y usar una base de datos H2 para mis pruebas de integración.
Maven tiene un comando para ejecutar pruebas: mvn test
.
¿Hay alguna manera de decirle a maven que inicie un servidor de base de datos H2 para las pruebas y detenerlo cuando esté listo?
Me imagino que esto funciona de forma similar a cómo puedo ejecutar tomcat a través de un comando Maven ( mvn tomcat:run
).
Lo siento si esta pregunta es absurda, todavía estoy envolviendo mi cabeza con nuevos conceptos.
Como H2 no proporciona el plugin Maven, deberías iniciarlo usando maven-antrun-plugin. Escriba el código para iniciar y detener el motor h2 en la tarea y llámelo cuando su prueba de integración comience y se detenga.
Ver detalles en http://docs.codehaus.org/display/MAVENUSER/Maven+and+Integration+Testing
Creo una base de datos H2 basada en archivos antes de ejecutar las pruebas unitarias. El archivo vive en el directorio de target
y se puede eliminar en cualquier momento usando mvn clean
.
Yo uso maven-sql-plugin de la siguiente manera:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>sql-maven-plugin</artifactId>
<version>1.5</version>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.166</version>
</dependency>
</dependencies>
<configuration>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:file:target/db/testdb</url>
<username>sa</username>
<password></password>
<autocommit>true</autocommit>
<skip>${maven.test.skip}</skip>
</configuration>
<executions>
<execution>
<id>create-db</id>
<phase>process-test-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<srcFiles>
<srcFile>${sql.dir}/drop_db.sql</srcFile>
<srcFile>${sql.dir}/tables.sql</srcFile>
<srcFile>${sql.dir}/constraints.sql</srcFile>
... etc ...
</srcFiles>
</configuration>
</execution>
</executions>
</plugin>
La base de datos se puede crear ejecutando mvn process-test-resources
. Cuando se ejecutan las pruebas, asegúrese de conectarse a la base de datos en target/db/testdb
través de las propiedades de hibernación.
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="org.h2.Driver"
p:url="jdbc:h2:file:target/db/testdb"
p:username="sa"
p:password="" />
También necesitarás una dependencia en com.h2database.h2 en las dependencias de maven.
En mi proyecto, para la prueba unitaria, solicité a Spring que manejara la creación e inicialización de esta base de datos. Como se indica en la documentación H2 , puede crear un bean para eso:
<bean id = "org.h2.tools.Server"
class="org.h2.tools.Server"
factory-method="createTcpServer"
init-method="start"
destroy-method="stop">
<constructor-arg value="-tcp,-tcpAllowOthers,true,-tcpPort,8043" />
</bean>
Simplemente necesita iniciar el contexto de Spring con esta configuración cuando comience las pruebas unitarias.
Este plugin funciona bien para generar un nuevo H2 DB con modo tcp antes de las pruebas de integración (la fase de complemento predeterminada): h2-maven-plugin en github
No está bien documentado, pero puede consultar las fuentes de Mojo para conocer las opciones de configuración. Está publicado en maven central.
Básicamente, para las pruebas de integración, es posible que desee que Maven:
- Reserve puertos de red disponibles al azar, para su servidor Tomcat y su H2 (para evitar conflictos en el puerto)
- Comience el servidor H2
- Inicie el servidor Tomcat
- Ejecute pruebas de integración
- Detener el servidor Tomcat
- Detener el servidor H2
Esto se puede lograr con una configuración de Maven que se vea así. Suponiendo que sus pruebas de integración se anotan con una interfaz personalizada JUnit Categoría:
@Category(IntegrationTest.class)
Esta configuración de Maven funciona bien para mí:
<profile>
<id>it</id>
<build>
<plugins>
<!-- Reserve randomly available network ports -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>reserve-network-port</id>
<goals>
<goal>reserve-network-port</goal>
</goals>
<phase>process-resources</phase>
<configuration>
<portNames>
<portName>tomcat.test.http.port</portName>
<portName>h2.test.tcp.port</portName>
</portNames>
</configuration>
</execution>
</executions>
</plugin>
<!-- Start H2 before integration tests, accepting tcp connections on the randomly selected port -->
<plugin>
<groupId>com.edugility</groupId>
<artifactId>h2-maven-plugin</artifactId>
<version>1.0</version>
<configuration>
<port>${h2.test.tcp.port}</port>
</configuration>
<executions>
<execution>
<id>Spawn a new H2 TCP server</id>
<goals>
<goal>spawn</goal>
</goals>
</execution>
<execution>
<id>Stop a spawned H2 TCP server</id>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Start Tomcat before integration tests on the -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<systemProperties>
<spring.profiles.active>integration_tests</spring.profiles.active>
<httpPort>${http.test.http.port}</httpPort>
<h2Port>${h2.test.tcp.port}</h2Port>
</systemProperties>
<port>${http.test.http.port}</port>
<contextFile>src/main/java/META-INF/tomcat/webapp-test-context-using-h2.xml</contextFile>
<fork>true</fork>
</configuration>
<executions>
<execution>
<id>run-tomcat</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>stop-tomcat</id>
<phase>post-integration-test</phase>
<goals>
<goal>shutdown</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
</plugin>
<!-- Run the integration tests annotated with @Category(IntegrationTest.class) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<!-- Bug in 2.12.x -->
<version>2.11</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>2.12.4</version>
</dependency>
</dependencies>
<configuration>
<groups>com.mycompany.junit.IntegrationTest</groups>
<failIfNoTests>false</failIfNoTests>
<junitArtifactName>junit:junit-dep</junitArtifactName>
<systemPropertyVariables>
<httpPort>${tomcat.test.http.port}</httpPort>
<h2Port>${h2.test.tcp.port}</h2Port>
</systemPropertyVariables>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
Es posible que desee utilizar filtros maven en el archivo de contexto tomcat para que el puerto sea reemplazado:
<contextFile>src/main/java/META-INF/tomcat/webapp-test-context-using-h2.xml</contextFile>
Con el contenido del archivo siendo:
<Resource name="jdbc/dataSource"
auth="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
username=""
password=""
driverClassName="org.h2.Driver"
url="jdbc:h2:tcp://localhost:${h2.test.tcp.port}/mem:db;DB_CLOSE_ON_EXIT=FALSE;MODE=MySQL"/>
O si no desea un origen de datos JNDI, puede usar un DataSource declarado por Spring, utilizando la misma propiedad ...
Un viaje adicional si desea poder configurar sus pruebas de integración tomcat y ejecutar las pruebas de integración desde su IDE:
Puede usar usar una propiedad para bifurcar o no el servidor de Tomcat:
<fork>${integrationTestsForkTomcatJvm}</fork>
Cuando configura fork = false, el servidor se bloqueará y maven no continuará, por lo que las pruebas de integración no se ejecutarán, pero podrá ejecutarlas desde su ide.
Pude hacer que funcionara sin usar un servidor externo simplemente agregando la dependencia a H2 a través de Maven y luego usando este bean:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:file:h2/db"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
Por otra parte, esto requiere que use una base de datos basada en archivos en lugar de en la memoria. Pero hace el truco.
Si desea hacerlo en la memoria, simplemente use una URL diferente:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:mem:db"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
Puede dar opciones adicionales, como:; DB_CLOSE_DELAY = -1
ver: http://www.h2database.com/html/features.html#in_memory_databases
puede crear 2 clases pequeñas con los métodos principales que inician y detienen la base de datos. la idea es ejecutar la clase StartServer antes de que se ejecuten las pruebas de integración y luego ejecutar StopServer después de que se hayan ejecutado las pruebas.
debe hacer lo mismo para su servidor de base de datos como se describe en algún lugar de este documento (la descripción es para iniciar y detener Jetty en las pruebas de integración)
en su pom.xml debe definir maven-exec-plugin para ejecutar el exec:java goal y crear 2 ejecuciones (1 para llamar a StartServer y 1 para StopServer):
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<!-- start server before integration tests -->
<id>start</id>
<phase>pre-integration-test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>com.foo.StartServer</mainClass>
</configuration>
</execution>
<execution>
<!-- stop server after integration tests -->
<id>stop</id>
<phase>post-integration-test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>com.foo.StopServer</mainClass>
</configuration>
</execution>
</executions>
</plugin>
espero que sea lo que quieras
siguiente hace el trabajo por mí (simplemente usando la dependencia h2
y el exec-maven-plugin
):
<build>
<plugins>
<!-- start/stop H2 DB as a server -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>start-h2</id>
<phase>pre-integration-test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.h2.tools.Server</mainClass>
<arguments>
<argument>-tcp</argument>
<argument>-tcpDaemon</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>stop-h2</id>
<phase>post-integration-test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.h2.tools.Server</mainClass>
<arguments>
<argument>-tcpShutdown</argument>
<argument>tcp://localhost:9092</argument>
</arguments>
</configuration>
</execution>
</executions>
<configuration>
<includeProjectDependencies>true</includeProjectDependencies>
<includePluginDependencies>true</includePluginDependencies>
<executableDependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</executableDependency>
</configuration>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.173</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
tenga en cuenta que en mi pom.xml
la base de datos com.h2database:h2
no era una dependencia del proyecto. En caso de que lo tengas, es posible que no necesites mencionarlo explícitamente como una dependencia de complemento.