Testcontainers для PostgreSQL и ClickHouse
↑ 4.3 Тестирование слоя данных · ← Предыдущая · → Следующая
Зачем это на собесе
Практическая реализация «тестов на настоящей БД» в CI.
Объяснение
public class PgFixture : IAsyncLifetime
{
private readonly PostgreSqlContainer _pg = new PostgreSqlBuilder()
.WithImage("postgres:16-alpine").WithDatabase("test").Build();
public string ConnectionString => _pg.GetConnectionString();
public async Task InitializeAsync()
{
await _pg.StartAsync();
await using var db = CreateContext();
await db.Database.MigrateAsync(); // реальные миграции проверяются тоже
}
public Task DisposeAsync() => _pg.DisposeAsync().AsTask();
public AppDbContext CreateContext() => new(new DbContextOptionsBuilder<AppDbContext>().UseNpgsql(ConnectionString).Options);
}
[CollectionDefinition("db")] public class DbCollection : ICollectionFixture<PgFixture> { }ClickHouse: new ClickHouseBuilder().WithImage("clickhouse/clickhouse-server:24").Build(), схема создаётся SQL-скриптом при старте.
Нюансы и подводные камни
- Один контейнер на коллекцию; не запускайте контейнер на каждый тест.
- В CI нужен доступ к Docker-демону (GitHub Actions: доступен по умолчанию).
- Фиксируйте версию образа как в продакшене.
- Порты случайны: используйте
GetConnectionString(). - Кэшируйте образы в CI, чтобы не тратить время на pull.
Практика
- Поднимите PostgreSQL через Testcontainers и прогоните миграции.
- Добавьте ClickHouse и протестируйте вставку батча.
- Замерьте время старта и подберите стратегию переиспользования.
Вопросы с ответами
Зачем прогонять миграции в тестах?
Проверяется, что схема, создаваемая миграциями, совместима с моделью и запросами.
Как ускорить тесты с контейнерами?
Один контейнер на коллекцию, очистка данных вместо пересоздания, кэш образов.