Ejecución de PostgreSQL solo en memoria

Quiero ejecutar una pequeña base de datos PostgreSQL que se ejecuta en memoria solamente, para cada prueba de unidad que escribo. Por ejemplo:

@Before void setUp() { String port = runPostgresOnRandomPort(); connectTo("postgres://localhost:"+port+"/in_memory_db"); // ... } 

Idealmente tendré un solo ejecutable postgres marcado en el control de versión, que usará la prueba unitaria.

Algo como HSQL , pero para postgres. ¿Cómo puedo hacer eso?

¿Puedo obtener una versión de Postgres? ¿Cómo puedo instruirlo para que no use el disco?

Esto no es posible con Postgres. No ofrece un motor en proceso / en memoria como HSQLDB o MySQL.

Si desea crear un entorno independiente, puede colocar los binarios de Postgres en SVN (pero es más que un solo ejecutable).

Tendrá que ejecutar initdb para configurar su base de datos de prueba antes de que pueda hacer algo con esto. Esto se puede hacer desde un archivo por lotes o usando Runtime.exec (). Pero ten en cuenta que initdb no es algo que sea rápido. Definitivamente no querrá ejecutar eso para cada prueba. Sin embargo, es posible que te salgas corriendo esto antes que tu suite de pruebas.

Sin embargo, mientras esto se puede hacer, recomendaría tener una instalación dedicada de Postgres donde simplemente recree su base de datos de prueba antes de ejecutar sus pruebas.

Puede volver a crear la base de datos de prueba utilizando una base de datos de plantillas que hace que la creación sea bastante rápida ( mucho más rápido que ejecutar initdb para cada ejecución de prueba)

O puede crear un TABLESPACE en ramfs / tempfs y crear todos sus objetos allí.
Hace poco me señalaron un artículo sobre hacer exactamente eso en Linux .

Advertencia

Esto puede poner en peligro la integridad de su clúster de base de datos completo .
Lea la advertencia agregada en el manual.
Entonces esta es solo una opción para datos prescindibles.

Para pruebas unitarias debería funcionar bien. Si está ejecutando otras bases de datos en la misma máquina, asegúrese de usar un clúster de base de datos separado (que tenga su propio puerto) para estar seguro.

(Moviendo mi respuesta del uso de PostgreSQL en memoria y generalizándolo):

No puede ejecutar Pg en proceso, en la memoria

No puedo entender cómo ejecutar la base de datos de Postgres en memoria para probar. ¿Es posible?

No, no es posible. PostgreSQL se implementa en C y se comstack a código de plataforma. A diferencia de H2 o Derby, no puedes simplemente cargar el jar y activarlo como un contenedor desechable en memoria.

A diferencia de SQLite, que también está escrito en C y comstackdo con código de plataforma, PostgreSQL tampoco se puede cargar en proceso. Requiere múltiples procesos (uno por conexión) porque es una architecture de multiprocesamiento, no de subprocesos múltiples. El requisito de multiprocesamiento significa que debe iniciar el administrador de correo como un proceso independiente.

En cambio: preconfigure una conexión

Sugiero simplemente escribir sus pruebas para esperar que un nombre de host / nombre de usuario / contraseña en particular funcione, y tener el arnés de prueba CREATE DATABASE como una base de datos desechable, luego DROP DATABASE al final de la ejecución. Obtenga los detalles de conexión de la base de datos de un archivo de propiedades, propiedades de destino de comstackción, variable de entorno, etc.

Es seguro usar una instancia de PostgreSQL existente, ya tienes bases de datos que te importan, siempre y cuando el usuario que proporciones a las pruebas de tu unidad no sea un superusuario, solo un usuario con derechos CREATEDB . En el peor, creará problemas de rendimiento en las otras bases de datos. Prefiero ejecutar una instalación de PostgreSQL completamente aislada para probar por ese motivo.

En cambio: lanzar una instancia de PostgreSQL desechable para probar

Alternativamente, si está realmente interesado, puede hacer que su arnés de prueba ubique los binarios de initdb y initdb , ejecute initdb para crear una base de datos, modifique pg_hba.conf para trust , ejecute postgres para iniciarlo en un puerto aleatorio, cree un usuario, cree un DB, y ejecuta las pruebas . Incluso podría empaquetar los binarios de PostgreSQL para múltiples architectures en un contenedor y descomprimir los de la architecture actual en un directorio temporal antes de ejecutar las pruebas.

Personalmente creo que es un gran dolor que debe evitarse; es mucho más fácil tener un DB de prueba configurado. Sin embargo, se ha vuelto un poco más fácil con la llegada del soporte include_dir en postgresql.conf ; ahora puede simplemente agregar una línea y luego escribir un archivo de configuración generado para el rest.

Pruebas más rápidas con PostgreSQL

Para obtener más información acerca de cómo mejorar de forma segura el rendimiento de PostgreSQL con fines de prueba, consulte una respuesta detallada que escribí sobre este tema anteriormente: Optimice PostgreSQL para pruebas rápidas

El dialecto PostgreSQL de H2 no es un verdadero sustituto

En cambio, algunas personas usan la base de datos H2 en el modo dialecto PostgreSQL para ejecutar pruebas. Creo que eso es casi tan malo como la gente de Rails que usa SQLite para probar y PostgreSQL para la implementación de producción.

H2 admite algunas extensiones PostgreSQL y emula el dialecto PostgreSQL. Sin embargo, es solo eso – una emulación. Encontrará áreas donde H2 acepta una consulta, pero PostgreSQL no, donde el comportamiento difiere, etc. También encontrarás muchos lugares donde PostgreSQL admite hacer algo que H2 simplemente no puede, como las funciones de ventana, en el momento de escribir.

Si comprende las limitaciones de este enfoque y su acceso a la base de datos es simple, H2 podría estar bien. Pero en ese caso, probablemente sea un mejor candidato para un ORM que abstraiga la base de datos porque de todos modos no está usando sus características interesantes, y en ese caso, ya no tiene que preocuparse por la compatibilidad de la base de datos.

¡Los espacios de tabla no son la respuesta!

No use un espacio de tabla para crear una base de datos “en memoria”. No solo es innecesario, ya que no ayudará significativamente al rendimiento de todos modos, sino que también es una excelente manera de interrumpir el acceso a cualquier otro que pueda interesarle en la misma instalación de PostgreSQL. La documentación de 9.4 ahora contiene la siguiente advertencia :

ADVERTENCIA

Aunque se encuentran fuera del directorio de datos principal de PostgreSQL, los espacios de tablas son una parte integral del clúster de la base de datos y no se pueden tratar como una colección autónoma de archivos de datos. Dependen de los metadatos contenidos en el directorio principal de datos y, por lo tanto, no se pueden adjuntar a un clúster de base de datos diferente ni se pueden hacer copias de seguridad de forma individual. De forma similar, si pierde un espacio de tabla (eliminación de archivos, falla de disco, etc.), el clúster de la base de datos puede volverse ilegible o no se puede iniciar. Colocar un tablespace en un sistema de archivos temporal como un ramdisk pone en riesgo la confiabilidad de todo el cluster.

porque noté que mucha gente estaba haciendo esto y se metía en problemas.

(Si ha hecho esto, puede mkdir el directorio de espacio de tablas que falta para que PostgreSQL comience nuevamente, luego DROP caer las bases de datos, tablas, etc. faltantes. Es mejor simplemente no hacerlo).

Ahora es posible ejecutar una instancia en memoria de PostgreSQL en sus pruebas JUnit a través del componente Embedded PostgreSQL de OpenTable: https://github.com/opentable/otj-pg-embedded .

Al agregar la dependencia a la biblioteca otj-pg-embedded ( https://mvnrepository.com/artifact/com.opentable.components/otj-pg-embedded ) puede iniciar y detener su propia instancia de PostgreSQL en su @Before y @Afer hooks:

 EmbeddedPostgres pg = EmbeddedPostgres.start(); 

Incluso ofrecen una regla JUnit para que JUnit inicie y detenga automáticamente su servidor de base de datos PostgreSQL:

 @Rule public SingleInstancePostgresRule pg = EmbeddedPostgresRules.singleInstance(); 

Puede usar TestContainers para hacer girar un contenedor de correo de PosgreSQL para pruebas: http://testcontainers.viewdocs.io/testcontainers-java/usage/database_containers/

TestContainers proporciona una JUnit @ Rule / @ ClassRule : este modo inicia una base de datos dentro de un contenedor antes de las pruebas y luego lo desglosa.

Ejemplo:

 public class SimplePostgreSQLTest { @Rule public PostgreSQLContainer postgres = new PostgreSQLContainer(); @Test public void testSimple() throws SQLException { HikariConfig hikariConfig = new HikariConfig(); hikariConfig.setJdbcUrl(postgres.getJdbcUrl()); hikariConfig.setUsername(postgres.getUsername()); hikariConfig.setPassword(postgres.getPassword()); HikariDataSource ds = new HikariDataSource(hikariConfig); Statement statement = ds.getConnection().createStatement(); statement.execute("SELECT 1"); ResultSet resultSet = statement.getResultSet(); resultSet.next(); int resultSetInt = resultSet.getInt(1); assertEquals("A basic SELECT query succeeds", 1, resultSetInt); } } 

También puede usar las configuraciones de configuración de PostgreSQL (como las que se detallan en la pregunta y la respuesta aceptada aquí ) para lograr el rendimiento sin recurrir necesariamente a una base de datos en memoria.