TGStat
TGStat
Введите текст для поиска
Расширенный поиск каналов
  • flag Russian
    Язык сайта
    flag Russian flag English flag Uzbek
  • Вход на сайт
  • Каталог
    Каталог каналов и чатов Региональные подборки Тематические подборки Платные каналы Поиск каналов
    Добавить канал/чат
  • Рейтинги
    Рейтинг каналов Рейтинг чатов Рейтинг публикаций
    Рейтинги брендов и персон
  • Аналитика
  • Поиск по публикациям
  • Мониторинг Telegram
  • Продвижение
    Реклама через Яндекс Бизнес Реклама в каналах через TGStat Agency Реклама на сайте TGStat.ru
C# 1001 notes

8 Jun, 19:30

Открыть в Telegram Поделиться Пожаловаться

🐳 «Используй Testcontainers вместо in-memory» - это только половина правды

Все уже выучили: EF Core InMemory provider - не интеграционный тест.

Он не ловит:

- баги в LINQ-трансляции
- ограничения БД
- коллации
- реальные типы колонок
- поведение конкретного SQL-провайдера

Окей, заменили на реальный PostgreSQL через Testcontainers. Победа? Не совсем.

Вот что начинается дальше.

1. Вы получили «медленное враньё» вместо «быстрого»

Поднимать контейнер на каждый тест-класс - быстрый способ превратить CI из 30 секунд в 8 минут.

Нормальный вариант:

- один контейнер на всю тестовую сессию
- изоляция данных между тестами через Respawn
- без пересоздания базы и контейнера каждый раз

Respawn чистит таблицы с учётом графа foreign keys за миллисекунды.

2. Транзакционный откат ≠ реальный сценарий

Трюк «обернули тест в транзакцию и откатили» красиво выглядит, но ломается, когда в коде есть:

- свои транзакции
- несколько SaveChanges
- фоновые операции
- поведение, завязанное на commit

В итоге тестируется сценарий, которого в проде нет.

3. Самая коварная ловушка - общий DbContext

Если тест и код используют один экземпляр DbContext, EF может вернуть данные из change tracker, а не из базы.

Тест зелёный, но он врёт: реальный SQL-запрос мог вообще не выполниться.

Между Act и Assert стоит чистить трекер:


Db.ChangeTracker.Clear();


4. Бонус, который теряют 90% команд - тест миграций

Реальная БД позволяет прогнать EF-миграции на чистой схеме.

Если миграция падает или схема разъехалась с моделью, вы узнаёте об этом в CI, а не в проде в пятницу вечером.

Пример базового подхода:


public class IntegrationTestBase : IAsyncLifetime
{
private static readonly PostgreSqlContainer _db =
new PostgreSqlBuilder()
.WithImage("postgres:16-alpine")
.Build();

private Respawner _respawner = null!;
protected AppDbContext Db = null!;

public async Task InitializeAsync()
{
await _db.StartAsync();

var options = new DbContextOptionsBuilder()
.UseNpgsql(_db.GetConnectionString())
.Options;

Db = new AppDbContext(options);

// Реальные миграции - заодно проверяем, что они накатываются
await Db.Database.MigrateAsync();

await using var conn = new NpgsqlConnection(_db.GetConnectionString());
await conn.OpenAsync();

_respawner = await Respawner.CreateAsync(conn, new RespawnerOptions
{
DbAdapter = DbAdapter.Postgres,
SchemasToInclude = ["public"]
});
}

// Сброс данных перед каждым тестом - без пересоздания контейнера
protected async Task ResetAsync()
{
await using var conn = new NpgsqlConnection(_db.GetConnectionString());
await conn.OpenAsync();

await _respawner.ResetAsync(conn);

// Иначе тест может читать из кеша, а не из БД
Db.ChangeTracker.Clear();
}

public Task DisposeAsync() => Task.CompletedTask;
}


Testcontainers - это не галочка «best practice», а смена философии.

Без нормальной изоляции данных вы просто пересели с быстрого вранья на медленное.

А как вы изолируете состояние БД между интеграционными тестами - Respawn, транзакции или пересоздание контейнера?

#dotnet #csharp #testing #efcore

1.7k 0 29 2
Каталог
Каталог каналов и чатов Подборки каналов Поиск каналов Добавить канал/чат
Рейтинги
Рейтинг каналов Telegram Рейтинг чатов Telegram Рейтинг публикаций Рейтинги брендов и персон
API
API статистики API поиска публикаций API Callback
Наши каналы
@TGStat @TGStat_Chat @telepulse @TGStatAPI
Почитать
Академия TGStat Исследование Telegram 2019 Исследование Telegram 2021 Исследование Telegram 2023
Контакты
Справочный центр Поддержка Почта Вакансии
Всякая всячина
Пользовательское соглашение Политика конфиденциальности Публичная оферта
Наши боты
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot