私が書いたユニットテストごとに、メモリのみで実行される小さなPostgreSQLデータベースを実行したいと思います。例えば:
@Before
void setUp() {
String port = runPostgresOnRandomPort();
connectTo("postgres://localhost:"+port+"/in_memory_db");
// ...
}
理想的には、単一のpostgres実行可能ファイルをバージョン管理にチェックインして、ユニットテストで使用するようにします。
HSQL
に似ていますが、postgres用です。どうやってやるの?
このようなPostgresバージョンを入手できましたか?ディスクを使用しないように指示するにはどうすればよいですか?
これはPostgresでは不可能です。 HSQLDBやMySQLのようなインプロセス/インメモリエンジンは提供しません。
自己完結型の環境を作成する場合は、PostgresバイナリをSVNに配置できます(ただし、実行可能ファイルは1つだけではありません)。
これで何かをする前に initdb を実行してテストデータベースをセットアップする必要があります。これは、バッチファイルから、またはRuntime.exec()を使用して実行できます。ただし、initdbは高速なものではないことに注意してください。あなたは間違いなく各テストに対してそれを実行したくないでしょう。ただし、テストスイートの前にこれを実行して逃げるかもしれません。
ただし、これは実行できますが、テストを実行する前にテストデータベースを再作成する専用のPostgresインストールをお勧めします。
テンプレートデータベースを使用してテストデータベースを再作成できます。テンプレートデータベースを使用すると、テストを実行するたびにinitdbを実行するよりも高速にlot作成できます。
(私の答えを in-memory PostgreSQLを使用 から移動して一般化):
テストのためにインメモリPostgresデータベースを実行する方法がわかりません。出来ますか?
いいえ、できません。 PostgreSQLはCで実装され、プラットフォームコードにコンパイルされます。 H2やDerbyとは異なり、jar
をロードして、それを使い捨てのインメモリDBとして起動することはできません。
Cで記述され、プラットフォームコードにコンパイルされるSQLiteとは異なり、PostgreSQLもインプロセスで読み込むことはできません。マルチスレッドではなく、マルチプロセッシングアーキテクチャであるため、複数のプロセス(接続ごとに1つ)が必要です。マルチプロセッシングの要件は、mustポストマスターをスタンドアロンプロセスとして起動することを意味します。
特定のホスト名/ユーザー名/パスワードが機能することを期待してテストを作成し、テストハーネスCREATE DATABASE
スローアウェイデータベース、実行の最後にDROP DATABASE
を作成することをお勧めします。プロパティファイルからデータベース接続の詳細を取得し、ターゲットプロパティ、環境変数などを構築します。
単体テストに指定するユーザーがnotスーパーユーザーである限り、すでに気にしているデータベースがある既存のPostgreSQLインスタンスを使用しても安全です、CREATEDB
権限を持つユーザーのみ。最悪の場合、他のデータベースでパフォーマンスの問題が発生します。そのため、テストのために完全に分離されたPostgreSQLインストールを実行することを好みます。
あるいは、本当に熱心なら テストハーネスにinitdb
とpostgres
のバイナリを見つけさせる、initdb
を実行してデータベースを作成し、pg_hba.conf
をtrust
に変更し、postgres
を実行してランダムポートで起動し、ユーザーを作成し、DBを作成して、テスト 。テストを実行する前に、jar内の複数のアーキテクチャ用のPostgreSQLバイナリをバンドルし、現在のアーキテクチャ用のものを一時ディレクトリに解凍することもできます。
個人的には、それは避けるべき大きな痛みだと思います。テストDBを構成するだけの方が簡単です。ただし、include_dir
のpostgresql.conf
サポートの出現により、少し簡単になりました。これで、1行追加するだけで、残りのすべてについて生成された構成ファイルを作成できます。
テスト目的でPostgreSQLのパフォーマンスを安全に改善する方法の詳細については、このトピックで以前に書いた詳細な回答を参照してください: Optimise高速テスト用のPostgreSQL
代わりに、PostgreSQLダイアレクトモードでH2データベースを使用してテストを実行する人もいます。これはRailsテストにSQLiteを使用し、実稼働展開にPostgreSQLを使用している人々とほぼ同じくらい悪いと思います。
H2はいくつかのPostgreSQL拡張機能をサポートし、PostgreSQLの方言をエミュレートします。ただし、それだけです-エミュレーション。 H2はクエリを受け入れますが、PostgreSQLは受け入れない、動作が異なるエリアなどを見つけるでしょう 。また、執筆時点でウィンドウ関数のように、PostgreSQLがH2ではできないことをサポートしている場所もたくさんあります。
このアプローチの制限を理解し、データベースへのアクセスが簡単な場合、H2は問題ないかもしれません。しかし、その場合は、おそらく興味深い機能を使用していないため、データベースを抽象化するORMのより良い候補です。その場合、データベースの互換性をこれ以上気にする必要はありません。
notは、テーブルスペースを使用して「メモリ内」データベースを作成します。とにかくパフォーマンスを大幅に向上させないため不要であるだけでなく、同じPostgreSQLインストールで気になる他のユーザーへのアクセスを中断する素晴らしい方法でもあります。 9.4のドキュメントには、次の警告が含まれるようになりました :
[〜#〜] warning [〜#〜]
メインのPostgreSQLデータディレクトリの外部にありますが、テーブルスペースはデータベースクラスターの不可欠な部分であり、データファイルの自律的なコレクションとして扱うことはできません。これらはメインデータディレクトリに含まれるメタデータに依存しているため、別のデータベースクラスターに接続したり、個別にバックアップしたりすることはできません。同様に、表領域が失われた場合(ファイルの削除、ディスクの障害など)、データベースクラスターが読み取り不能になるか、起動できなくなる可能性があります。 ramdiskのような一時ファイルシステムにテーブルスペースを配置すると、クラスター全体の信頼性が低下します。
あまりにも多くの人がこれをしてトラブルに直面していることに気づいたからです。
(これを行った場合、mkdir
不足しているテーブルスペースディレクトリを使用してPostgreSQLを再起動し、DROP
不足しているデータベース、テーブルなどを使用できます。
または、ramfs/tempfsで [〜#〜] tablespace [〜#〜] を作成し、そこにすべてのオブジェクトを作成できます。
最近、 Linuxでそれを正確に行うことに関する記事 を指摘されました。
これは、データベースクラスター全体の整合性を危険にさらす可能性があります。
マニュアルに追加された警告をお読みください。
したがって、これは消耗データのオプションにすぎません。
unit-testingの場合、問題なく動作するはずです。同じマシン上で他のデータベースを実行している場合は、安全のために、個別のデータベースクラスター(独自のポートを持つ)を使用してください。
OpenTableの埋め込みPostgreSQLコンポーネントを使用して、JUnitテストでPostgreSQLのメモリ内インスタンスを実行できるようになりました: https://github.com/opentable/otj-pg-embedded 。
依存関係をotj-pg-embeddedライブラリに追加することで( https://mvnrepository.com/artifact/com.opentable.components/otj-pg-embedded )、独自のインスタンスを起動および停止できます。 @Beforeおよび@AferフックでのPostgreSQLの例:
EmbeddedPostgres pg = EmbeddedPostgres.start();
さらに、JUnitがPostgreSQLデータベースサーバーを自動的に開始および停止するJUnitルールを提供します。
@Rule
public SingleInstancePostgresRule pg = EmbeddedPostgresRules.singleInstance();
TestContainers を使用して、テスト用にPosgreSQLドッカーコンテナーを起動できます。 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);
}
}
現在、ロシア語検索会社の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));");
しばらく使用しています。うまくいきます。
[〜#〜] updated [〜#〜]:このプロジェクトはもう積極的にメンテナンスされていません
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.
また、PostgreSQLの構成設定(質問や受け入れられた回答 here で詳しく説明されている設定など)を使用して、必ずしもメモリ内データベースに頼らずにパフォーマンスを達成することもできます。