我想运行一个只在内存中运行的小型PostgreSQL数据库,用于我编写的每个单元测试。例如:
@Before
void setUp() {
String port = runPostgresOnRandomPort();
connectTo("postgres://localhost:"+port+"/in_memory_db");
// ...
}
理想情况下,我会在版本控件中检查一个postgres可执行文件,单元测试将使用该文件。
像HSQL
这样的东西,但对于postgres。我怎么能这样做?
我可以获得这样的Postgres版本吗?如何指示它不要使用磁盘?
答案 0 :(得分:65)
或者您可以在ramfs / tempfs中创建TABLESPACE并在那里创建所有对象 我最近指的是article about doing exactly that on Linux。
这可能会危及整个数据库群集的完整性
Read the added warning in the manual.
所以这只是消耗性数据的一种选择。
对于单元测试,它应该可以正常工作。如果您在同一台计算机上运行其他数据库,请确保使用单独的数据库集群(具有自己的端口)是安全的。
答案 1 :(得分:64)
(将我的答案从Using in-memory PostgreSQL移开并概括):
我无法弄清楚如何运行内存Postgres数据库进行测试。有可能吗?
不,这是不可能的。 PostgreSQL在C中实现并编译为平台代码。与H2或Derby不同,您不能只加载jar
并将其作为一次性内存数据库启动。
与SQLite(也是用C语言编写并编译为平台代码)不同,PostgreSQL也无法在进程中加载。它需要多个进程(每个连接一个),因为它是一个多处理,而不是多线程架构。多处理要求意味着您必须将postmaster作为独立进程启动。
我建议您只需编写测试以期望特定的主机名/用户名/密码可用,并让测试工具CREATE DATABASE
成为一次性数据库,然后在运行结束时使用DROP DATABASE
。从属性文件,构建目标属性,环境变量等获取数据库连接详细信息
使用您已经拥有的数据库的现有PostgreSQL实例是安全的,只要您提供给单元测试的用户不超级用户,只有{{1的用户权利。在最坏的情况下,您将在其他数据库中创建性能问题。我更喜欢运行完全独立的PostgreSQL安装进行测试。
或者,如果您真的非常,那么你可以have your test harness locate the initdb
and postgres
binaries, run initdb
to create a database, modify pg_hba.conf
to trust
, run postgres
to start it on a random port, create a user, create a DB, and run the tests。您甚至可以在jar中捆绑多个体系结构的PostgreSQL二进制文件,并在运行测试之前将当前体系结构的二进制文件解压缩到一个临时目录。
我个人认为这是一个应该避免的主要痛苦;只需配置一个测试数据库就更容易了。但是,CREATEDB
中include_dir
支持的出现变得更加容易;现在你可以只追加一行,然后为所有其余部分写一个生成的配置文件。
有关如何安全地提高PostgreSQL性能以进行测试的更多信息,请参阅我之前就此主题撰写的详细答案:Optimise PostgreSQL for fast testing
有些人在PostgreSQL方言模式下使用H2数据库来运行测试。我认为这几乎和使用SQLite进行测试和使用PostgreSQL进行生产部署的Rails人一样糟糕。
H2支持一些PostgreSQL扩展并模拟PostgreSQL方言。然而,就是这样 - 仿真。 You'll find areas where H2 accepts a query but PostgreSQL doesn't, where behaviour differs, etc。在撰写本文时,你还会发现很多地方PostgreSQL支持H2做的事情 - 就像窗口函数一样。
如果您了解此方法的局限性并且数据库访问很简单,那么H2可能没问题。但在这种情况下,你可能是抽象数据库的ORM的更好的候选者,因为你还没有使用它有趣的功能 - 在这种情况下,你不必再那么关心数据库的兼容性。
不使用表空间来创建“内存中”数据库。它不仅没有必要,因为它无论如何都不会显着提高性能,但它也是一种很好的方法来破坏对同一PostgreSQL安装中你可能关心的任何其他内容的访问。 The 9.4 documentation now contains the following warning:
警告
即使位于主PostgreSQL数据目录之外, 表空间是数据库集群的组成部分,不可能 被视为数据文件的自治集合。他们是依赖的 在主数据目录中包含的元数据,因此不能 附加到不同的数据库集群或单独备份。 同样,如果丢失了表空间(文件删除,磁盘故障, 等),数据库集群可能变得不可读或无法启动。 将表空间放在像ramdisk这样的临时文件系统上会带来风险 整个集群的可靠性。
因为我注意到有太多人这样做并遇到麻烦。
(如果你已经这样做了,你可以postgresql.conf
丢失的表空间目录以使PostgreSQL重新启动,然后mkdir
丢失的数据库,表等。最好不要这样做。)
答案 2 :(得分:35)
Postgres无法做到这一点。它不提供像HSQLDB或MySQL那样的进程内/内存引擎。
如果你想创建一个自包含的环境,你可以将Postgres二进制文件放入SVN(但它不仅仅是一个可执行文件)。
您需要先运行initdb来设置测试数据库,然后才能执行此操作。这可以通过批处理文件或使用Runtime.exec()来完成。但请注意,initdb不是那么快的东西。你肯定不想为每个测试运行它。你可能会在测试套件之前运行它。
然而,虽然可以这样做,但我建议您使用专门的Postgres安装,只需在运行测试之前重新创建测试数据库。
您可以使用模板数据库重新创建测试数据库,这样可以非常快速地创建测试数据库(很多比为每次测试运行运行initdb更快)
答案 3 :(得分:21)
现在可以通过OpenTable中的嵌入式PostgreSQL组件在JUnit测试中运行PostgreSQL的内存实例:https://github.com/opentable/otj-pg-embedded。
通过将依赖项添加到otj-pg嵌入式库(https://mvnrepository.com/artifact/com.opentable.components/otj-pg-embedded),您可以在@Before和@Afer挂钩中启动和停止自己的PostgreSQL实例:
class User {
static belongsTo = { account: Account }
Role role
}
他们甚至提供了一个JUnit规则来自动让JUnit为您启动和停止PostgreSQL数据库服务器:
def addRep(manager) {
User rep = new User( account: manager.account,
role: Role.REP)
rep.save(flush: true, failOnError: true)
}
答案 4 :(得分:9)
您可以使用TestContainers启动PosgreSQL docker容器进行测试: http://testcontainers.viewdocs.io/testcontainers-java/usage/database_containers/
TestContainers提供 JUnit @ Rule / @ ClassRule :此模式在测试之前启动容器内的数据库,然后将其撕掉。
示例:
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);
}
}
答案 5 :(得分:3)
现在有一个来自俄罗斯搜索公司Yandex的内存版本的PostgreSQL:https://github.com/yandex-qatools/postgresql-embedded
它基于Flapdoodle OSS的嵌入过程。
使用示例(来自github页面)
// starting Postgres
final EmbeddedPostgres postgres = new EmbeddedPostgres(V9_6);
// predefined data directory
// final EmbeddedPostgres postgres = new EmbeddedPostgres(V9_6, "/path/to/predefined/data/directory");
final String url = postgres.start("localhost", 5432, "dbName", "userName", "password");
// connecting to a running Postgres and feeding up the database
final Connection conn = DriverManager.getConnection(url);
conn.createStatement().execute("CREATE TABLE films (code char(5));");
我正在使用它一段时间。效果很好。
已更新:该项目不再得到积极维护
Please be adviced that the main maintainer of this project has successfuly
migrated to the use of Test Containers project. This is the best possible
alternative nowadays.
答案 6 :(得分:3)
如果您使用的是NodeJS,则可以使用pg-mem(免责声明:我是作者)来模仿postgres数据库的最常见功能。
您将拥有一个完整的内存中,独立于平台且与平台无关的数据库,可以复制PG行为(甚至是runs in browsers)。
我写了一篇文章来展示如何在您的单元测试here中使用它。
答案 7 :(得分:2)
您还可以使用PostgreSQL配置设置(例如问题中详述的那些设置和接受的答案here)来实现性能,而无需使用内存数据库。
答案 8 :(得分:0)
如果你可以使用docker,你可以在内存中挂载postgresql数据目录进行测试
readAsText