Запуск PostgreSQL только в памяти

Я хочу запустить небольшую базу данных PostgreSQL, которая работает только в памяти, для каждого модульного теста, который я пишу. Например:

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

В идеале у меня будет один исполняемый файл postgres, зарегистрированный в системе управления версиями, который будет использоваться модульным тестом.

что-то вроде HSQL, но для postgres. Как я могу это сделать?

могу ли я получить такую версию Postgres? Как я могу проинструктировать его не использовать диск?

6 ответов


Это невозможно с Postgres. Он не предлагает движок в процессе/в памяти, такой как HSQLDB или MySQL.

Если вы хотите создать автономную среду, вы can поместите двоичные файлы Postgres в SVN (но это больше, чем один исполняемый файл).

вам нужно будет запустить initdb, указав чтобы настроить тестовую базу данных, прежде чем вы сможете что-либо с этим сделать. Это можно сделать из пакетного файла или с помощью среды выполнения.выполнение.)( Но заметьте, что initdb-это не то, что быстро. Вы определенно не захотите запускать это для каждого теста. Вы можете уйти, запустив это до вашего набора тестов.

однако, хотя это можно сделать, я бы рекомендовал иметь специальную установку Postgres, где вы просто воссоздаете свою тестовую базу данных перед запуском тестов.

вы можете повторно создать тестовую базу данных, используя базу данных шаблонов, что делает ее создание довольно быстрым (a много быстрее, чем работает initdb для каждого тестового запуска)


или вы можете создать пространство в ramfs / tempfs и создайте там все свои объекты.
Недавно мне указали на статья о том, как сделать именно это в Linux.

предупреждение

Это может поставить под угрозу целостность вашей весь кластер баз данных.
прочитайте добавленное предупреждение в руководстве.
Таким образом, это только вариант для расходных данных.

для юнит-тестирования он должен работать просто отлично. Если вы используете другие базы данных на том же компьютере, обязательно используйте отдельный кластер баз данных (который имеет свой собственный порт).


(перемещая мой ответ из использование в памяти PostgreSQL и обобщая ее):

вы не можете запустить Pg в процессе, в памяти

я не могу понять, как запустить базу данных Postgres в памяти для тестирования. Возможно ли это?

нет, это невозможно. PostgreSQL реализован на языке C и скомпилирован в код платформы. В отличие от H2 или Derby, вы не можете просто загрузить jar и запустите его как выброс в памяти ДЕЦИБЕЛ.

в отличие от SQLite, который также написан на C и скомпилирован в код платформы, PostgreSQL также не может быть загружен в процесс. Для этого требуется несколько процессов (по одному на соединение), потому что это многопроцессорная, а не многопоточная архитектура. Требование многопроцессорной обработки означает, что вы должны запустите postmaster как автономный процесс.

: установите связь

я предлагаю просто писать тесты, чтобы ожидать конкретное имя/логин/пароль для работы и тестирования CREATE DATABASE одноразовая базе, то DROP DATABASE в конце прогона. Получите сведения о соединении с базой данных из файла свойств, создайте целевые свойства, переменную среды и т. д.

безопасно использовать существующий экземпляр PostgreSQL, в котором у вас уже есть базы данных, о которых вы заботитесь, до тех пор, пока пользователь, которого вы предоставляете в модульные тесты,не суперпользователь, только пользователь с CREATEDB прав. На в худшем случае вы создадите проблемы с производительностью в других базах данных. По этой причине я предпочитаю запускать полностью изолированную установку PostgreSQL для тестирования.

вместо этого: запустите одноразовый экземпляр PostgreSQL для тестирования

если вы действительно keen вы могли бы ваш теста найдите initdb и postgres файлы, запустите initdb создать базу данных, изменить pg_hba.conf to trust, используя postgres чтобы запустить его на случайном порту, создайте пользователь, создайте БД и запустите тесты. Вы даже можете связать двоичные файлы PostgreSQL для нескольких архитектур в jar и распаковать их для текущей архитектуры во временный каталог перед запуском тестов.

лично я думаю, что это серьезная боль, которой следует избегать; проще просто настроить тестовую БД. Тем не менее, с появлением include_dir поддержка в postgresql.conf, теперь вы можете просто добавить одну строку, а затем написать сгенерированный конфигурационный файл для всех остальных.

более быстрое тестирование с помощью PostgreSQL

для получения дополнительной информации о том, как безопасное улучшите производительность PostgreSQL для целей тестирования, см. подробный ответ, который я написал на эту тему ранее:оптимизация PostgreSQL для быстрого тестирования

диалект PostgreSQL H2 не является истинной заменой

некоторые люди вместо этого используют базу данных H2 в режиме диалекта PostgreSQL для запуска тесты. Я думаю, что это почти так же плохо, как люди Rails, использующие SQLite для тестирования и PostgreSQL для развертывания производства.

H2 поддерживает некоторые расширения PostgreSQL и эмулирует диалект PostgreSQL. Однако это всего лишь подражание. вы найдете области, где H2 принимает запрос, но PostgreSQL-нет, где поведение отличается и т. д.. Вы также найдете множество мест, где PostgreSQL поддерживает то, что H2 просто не может - как оконные функции, в время написания.

если вы понимаете ограничения этого подхода и ваш доступ к базе данных прост, H2 может быть в порядке. Но в этом случае вы, вероятно, лучший кандидат на ORM, который абстрагирует базу данных, потому что вы все равно не используете ее интересные функции, и в этом случае вам больше не нужно заботиться о совместимости базы данных.

табличные пространства не являются ответом!

Do не используйте табличное пространство для создание "базы данных". Это не только не нужно, так как это не поможет производительности значительно в любом случае, но это также отличный способ нарушить доступ к любому другому, о котором вы можете заботиться в той же установке PostgreSQL. документация 9.4 теперь содержит следующее предупреждение:

предупреждение

несмотря на то, что находится вне основного каталога данных PostgreSQL, табличные пространства являются неотъемлемой частью кластера базы данных и не может быть рассматривается как автономный набор файлов данных. Они зависимы на метаданные, содержащиеся в основном каталоге данных, и поэтому не могут быть присоединен к другому кластеру базы данных или резервное копирование в отдельности. Аналогично, если вы потеряете табличное пространство (удаление файла, сбой диска, etc), кластер базы данных может стать нечитаемым или неспособным к запуску. Размещение табличного пространства во временной файловой системе подобно ramdisk рискует надежность всего группа.

потому что я заметил, что слишком много людей делают это и сталкиваются с проблемами.

(если вы сделали это вы можете mkdir отсутствующий каталог табличных пространств, чтобы запустить PostgreSQL снова, затем DROP отсутствующих баз данных, таблиц и т. д. Лучше просто не делать этого.)


теперь можно запустить экземпляр PostgreSQL в памяти в тестах JUnit через встроенный компонент PostgreSQL из OpenTable:https://github.com/opentable/otj-pg-embedded.

путем добавления зависимости в библиотеку otj-pg-embedded (https://mvnrepository.com/artifact/com.opentable.components/otj-pg-embedded) Вы можете запустить и остановить свой собственный экземпляр PostgreSQL в @Before и @ Afer hooks:

EmbeddedPostgres pg = EmbeddedPostgres.start();

Они даже предложите правило JUnit для автоматического запуска и остановки сервера базы данных PostgreSQL для вас:

@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);
    }
}

вы также можете использовать настройки конфигурации PostgreSQL (например, подробные в вопросе и принятом ответе здесь) для достижения производительности, не обязательно прибегая к базе данных в памяти.