Skip to content

Latest commit

 

History

History
52 lines (41 loc) · 7.92 KB

File metadata and controls

52 lines (41 loc) · 7.92 KB

Раздел 14. Обработка ошибок и Тестирование

В .NET обработка ошибок и тестирование — это во многом «истории фреймворков»: исключения встроены в CLR и пронизывают весь BCL, а тесты пишутся на внешних xUnit/NUnit/MSTest с Moq и FluentAssertions поверх. В Go оба подхода устроены принципиально иначе. Ошибки здесь — это обычные значения, которые функция возвращает и которые вы явно проверяете; никакого скрытого «всплытия» через стек. А тестирование — это встроенный в язык и тулчейн инструмент (testing + go test), дополненный кодогенерацией моков, а не рантайм-магией динамических прокси.

Этот раздел — финальный мостик от .NET-привычек «бросить исключение и поймать выше» и «подключить тест-фреймворк» к идиомам Go: явный возврат error, оборачивание через %w, table-driven тесты, моки на интерфейсах и интеграционные тесты на реальных зависимостях через Testcontainers.

Цели обучения

  • Понять, почему в Go ошибки — это значения (error — интерфейс), а не исключения, и привыкнуть к идиоме if err != nil.
  • Создавать и оборачивать ошибки (errors.New, fmt.Errorf с %w) и распаковывать цепочки через errors.Is, errors.As, errors.Unwrap, errors.Join.
  • Различать sentinel-ошибки и кастомные типы ошибок и понимать, когда какой инструмент уместен.
  • Применять panic/recover строго по назначению — для действительно исключительных ситуаций и на границах, а не вместо ошибок.
  • Знать точную механику defer/panic/recover: когда вычисляются аргументы defer, ловушку defer-в-цикле, изменение именованного возврата, правила recover и конвертацию panic→error.
  • Писать тесты на встроенном testing: подтесты (t.Run), параллелизм, table-driven как главную идиому, покрытие, бенчмарки, Example-тесты и фаззинг.
  • Строить моки на интерфейсах (вручную и через кодогенерацию mockery/gomock) и поднимать реальные зависимости в Docker через testcontainers-go.
  • Осознанно сопоставить .NET-стек (исключения, xUnit, Moq) с Go-подходом и видеть плюсы и минусы каждого.

Содержание раздела

  1. Обработка ошибок — ошибки как значения, интерфейс error, if err != nil, оборачивание через %w, errors.Is/As/Unwrap/Join, sentinel-ошибки и кастомные типы, введение в panic/recover и defer.
  2. defer, panic и recover — механика и ловушки: когда вычисляются аргументы defer, LIFO, defer-в-цикле, изменение именованного возврата; что делает panic (раскрутка стека, стектрейс, выход 2); точные правила recover и паттерн panic→error.
  3. Тестирование — встроенный testing, файлы _test.go, t.Run/t.Parallel/t.Helper/t.Cleanup, table-driven tests, покрытие, бенчмарки, Example-тесты, фаззинг и testify.
  4. Моки и Testcontainers — моки на интерфейсах, ручные моки vs кодогенерация (mockery, gomock), интеграционные тесты на реальных зависимостях через testcontainers-go.
  5. Сравнение с .NET — консолидированный мостик: исключения против значений-ошибок, тест-фреймворки против встроенного testing, динамические моки против кодогенерации.

Ориентир: что в .NET → что в Go

Держите таблицу под рукой при чтении раздела. Детали каждого сопоставления разбираются в соответствующих главах.

Концепция в .NET Аналог в Go Ключевое различие
throw / возбуждение исключения return ..., err Ошибка — обычное возвращаемое значение, а не аварийное всплытие по стеку
try/catch if err != nil { ... } Поток обработки виден в коде; нет скрытых точек выхода
finally / using defer defer отрабатывает при выходе из функции, в т.ч. при panic
InnerException / new Ex(..., inner) fmt.Errorf("...: %w", err) Цепочка строится глаголом %w, а не свойством
catch (SpecificException e) errors.As(err, &target) Извлечение конкретного типа из цепочки
Сравнение с конкретным исключением errors.Is(err, ErrSentinel) Сравнение с заранее объявленным значением-маркером
AggregateException errors.Join(err1, err2) (Go 1.20) Объединение нескольких ошибок в одну
throw; (рефолд) / throw new(...) panic(...) panic — только для невосстановимых ситуаций
catch на верхнем уровне recover() в defer Восстановление строго на границе (например, middleware)
xUnit/NUnit/MSTest встроенный пакет testing Тест-раннер — часть тулчейна (go test), не внешний пакет
[Fact] / метод-тест func TestXxx(t *testing.T) Конвенция имени вместо атрибута
[Theory] + [InlineData] table-driven tests Слайс кейсов + цикл с t.Run, а не атрибуты
[Theory] + [MemberData] слайс структур-кейсов Данные — обычный Go-код
FluentAssertions / Assert.* t.Error/t.Fatal или testify stdlib даёт минимум; testify — популярный сторонний слой
Moq / NSubstitute (рантайм-прокси) mockery / gomock (кодогенерация) Мок генерируется на этапе сборки из интерфейса
BenchmarkDotNet func BenchmarkXxx(b *testing.B) Бенчмарки встроены в go test
Testcontainers for .NET testcontainers-go Тот же проект, тот же подход — реальные зависимости в Docker

⌂ Главная · → Следующий: Обработка ошибок