В прошлом совете упоминались чистые функции в базе. Разумеется, их нужно тестировать. Для Постгреса написаны свои тестовые фреймворки, но ими пользуются при разработке расширений. Обычные функции тестируют в приложении: вызывают функцию и проверяют, что она вернула.

Например, в базе есть функция для форматирования центов:

create or replace function format_cents(cents integer)
returns text
immutable strict parallel safe language sql
return to_char(cents, '999.999');

Тест посылает такой запрос:

select
 x,
 format_cents(x) as result
from (values
 (1), (999), (null), (0), (-42)) as vals(x);

Читаем результат и проверяем, что он следующий:

┌────────┬──────────┐
│   x    │  result  │
├────────┼──────────┤
│      1 │    1.000 │
│    999 │  999.000 │
│ <null> │ <null>   │
│      0 │     .000 │
│    -42 │  -42.000 │
└────────┴──────────┘

Вот и все. Если кто-то поправит функцию, тест упадет.

Сложную логику тестируют точно так же. Достаточно нескольких шагов:

  • положить нужные данные в базу;
  • запустить целевую функцию;
  • проверить, что данные изменились должным образом;
  • почистить за собой.

Функция удобна тем, что данные не нужно готовить. Передал — получил. База фактически не участвует. А для сложной логики нужно готовить данные.

К счастью, для этого есть фикстуры — функции, которые выполняются до или после теста, причем в разрезе всего набора или отдельного теста. Поэтому пишутся фикстуры, которые поднимают базу, накатывают тестовые данные, а в конце делают TRUNCATE по всем таблицам.

Базу обычно запускают в Докере, потому что в нем многое можно задать из коробки (базу, пользователя, пароль, начальные .sql файлы и другое). Кто не любит Докер, пусть ставит локальный Постгрес — он есть везде.

На этом месте начинаются вопли: мол, тесты-то не юнит-, а интеграционные! Ну и что? Юнит-тесты нужны, но порой их недостаточно. Когда сетевые вызовы закрыты моками, легко оказаться в мире Оруэлла: дважды два равно пяти. Тесты пробегают, прод падает.

Так что если у вас Постгрес — тестируйте, как приложение ходит в Постгрес.