私が書くユニットテストごとに、メモリ内でのみ実行される小さな PostgreSQL データベースを実行したいと考えています。たとえば、次のようになります。
@Before
void setUp() {
String port = runPostgresOnRandomPort();
connectTo("postgres://localhost:"+port+"/in_memory_db");
// ...
}
理想的には、ユニット テストで使用する単一の postgres 実行可能ファイルをバージョン管理にチェックインします。
のようなものですHSQL
が、postgres 用です。どうすればできますか?
このような Postgres バージョンはどこで入手できますか? ディスクを使用しないように指示するにはどうすればよいですか?
ベストアンサー1
(私の回答をインメモリPostgreSQLの使用そしてそれを一般化する):
Pgをインプロセス、インメモリで実行することはできません
テスト用にインメモリ Postgres データベースを実行する方法がわかりません。 可能ですか?
いいえ、それは不可能です。PostgreSQL は C で実装され、プラットフォーム コードにコンパイルされます。H2 や Derby とは異なり、単にロードしてjar
使い捨てのメモリ内 DB として起動することはできません。
そのストレージはファイルシステムベースであり、純粋にメモリ内のデータストアを使用できるような組み込みのストレージ抽象化は備えていません。できるただし、ramdisk、tempfs、またはその他の一時的なファイル システム ストレージを指定する必要があります。
C言語で書かれ、プラットフォームコードにコンパイルされるSQLiteとは異なり、PostgreSQLはインプロセスでロードできません。マルチスレッドではなくマルチプロセスアーキテクチャであるため、複数のプロセス(接続ごとに1つ)が必要です。マルチプロセス要件は、しなければならないポストマスターをスタンドアロン プロセスとして起動します。
使い捨て容器を使用する
私が最初にこれを書いたときから、コンテナの使用は広く普及し、よく理解され、簡単になりました。
テスト用にDockerコンテナに使い捨てのPostgresインスタンスを設定し、最後にそれを破棄するのは簡単なはずです。LD_PRELOAD
次のようなハックでスピードアップできます。 libeatmydata
厄介な「クラッシュ時にデータをひどく破損させない」機能を無効にします ;)。
任意のテスト スイート、言語、またはツールチェーンに対してこれを自動化するラッパーが多数あります。
代替案: 接続を事前設定する
(コンテナ化が容易になる前に書かれたものなので、現在は推奨されていません)
特定のホスト名/ユーザー名/パスワードが機能することを想定してテストを作成し、テストでCREATE DATABASE
使い捨てのデータベースを利用して、DROP DATABASE
実行の最後にプロパティ ファイル、ビルド ターゲット プロパティ、環境変数などからデータベース接続の詳細を取得することをお勧めします。
すでに関心のあるデータベースがある既存のPostgreSQLインスタンスを使用しても安全です。ただし、ユニットテストに指定するユーザーがないスーパーユーザー、権限を持つユーザーのみCREATEDB
。最悪の場合、他のデータベースでパフォーマンスの問題が発生します。そのため、テストには完全に分離された PostgreSQL インストールを実行することを好みます。
代わりに、テスト用に使い捨てのPostgreSQLインスタンスを起動します。
あるいは、もしあなたが本当に熱心にテストハーネスでinitdb
とpostgres
バイナリを見つけ、 を実行してinitdb
データベースを作成し、pg_hba.conf
に変更しtrust
、を実行してpostgres
ランダムポートで起動し、ユーザーを作成し、DB を作成して、テストを実行します。複数のアーキテクチャ用の PostgreSQL バイナリを jar にバンドルし、テストを実行する前に現在のアーキテクチャ用のバイナリを一時ディレクトリに解凍することもできます。
個人的には、これは避けるべき大きな問題だと思います。テスト DB を構成する方がはるかに簡単です。ただし、のinclude_dir
サポートの登場により、少し簡単になりましたpostgresql.conf
。今では、1 行追加するだけで、残りのすべての構成ファイルを生成して記述できます。
PostgreSQLによるテストの高速化
詳細については、安全にテスト目的で PostgreSQL のパフォーマンスを向上させるには、このトピックについて以前に書いた詳細な回答を参照してください。PostgreSQLを最適化して高速テストを実現
H2のPostgreSQL方言は真の代替ではない
代わりに、PostgreSQL 方言モードで H2 データベースを使用してテストを実行する人もいます。これは、Rails ユーザーがテストに SQLite を使用し、本番環境のデプロイメントに PostgreSQL を使用するのと同じくらい悪いことだと思います。
H2 はいくつかの PostgreSQL 拡張機能をサポートし、PostgreSQL 方言をエミュレートします。ただし、それは単なるエミュレーションです。H2 ではクエリが受け入れられるが PostgreSQL では受け入れられない部分や、動作が異なる部分などが見つかるでしょう。また、執筆時点ではウィンドウ関数など、H2 ではできないことを PostgreSQL がサポートしている場所も多数あります。
このアプローチの制限を理解していて、データベースへのアクセスが単純な場合は、H2 でも問題ないかもしれません。しかし、その場合は、データベースの興味深い機能を使用しないので、データベースを抽象化する ORM の方が適している可能性があります。その場合は、データベースの互換性についてそれほど気にする必要がなくなります。
テーブルスペースは答えではありません!
するないテーブルスペースを使用して「メモリ内」データベースを作成します。いずれにしてもパフォーマンスに大きく貢献しないので不必要なだけでなく、同じ PostgreSQL インストール内の他の重要なデータベースへのアクセスを妨害する優れた方法でもあります。9.4のドキュメントには次の警告が含まれています:
警告
テーブルスペースは、PostgreSQL のメイン データ ディレクトリの外部に配置されていますが、データベース クラスターの不可欠な部分であり、データ ファイルの独立したコレクションとして扱うことはできません。テーブルスペースはメイン データ ディレクトリに含まれるメタデータに依存しているため、別のデータベース クラスターに接続したり、個別にバックアップしたりすることはできません。同様に、テーブルスペースが失われると (ファイルの削除、ディスク障害など)、データベース クラスターが読み取り不能になったり、起動できなくなったりする可能性があります。RAM ディスクなどの一時ファイル システムにテーブルスペースを配置すると、クラスター全体の信頼性が損なわれる可能性があります。
あまりにも多くの人がこれをやってトラブルに巻き込まれていることに気づいたからです。
(これを行った場合、mkdir
不足しているテーブルスペース ディレクトリを使用して PostgreSQL を再起動し、DROP
不足しているデータベース、テーブルなどを削除できます。これを行わない方がよいでしょう。)